Scoped credentials
Generate keys from Hotel Dashboard -> Property Sync or External Website. Copy the full secret once and store only on the server.
Property Sync API
Property Sync lets a hotel keep an existing website or booking system while sending rooms, categories, bookings, check-ins, and availability data into MafrexAI with a scoped server-side key.
Use mfx_sync_... keys for operational data. Use mfx_pay_... keys only for payment orders. Keeping them separate prevents one leaked payment credential from creating rooms, bookings, or check-in records.
Generate keys from Hotel Dashboard -> Property Sync or External Website. Copy the full secret once and store only on the server.
Write endpoints support Idempotency-Key so an interrupted sync can be retried without duplicate records.
MafrexAI can notify the external system when a MafrexAI-originated room booking is confirmed.
Every request must be made from the external system server. The full key is shown once, then MafrexAI stores only its hash and metadata.
Authorization: Bearer mfx_sync_your_key
Idempotency-Key: atican-rooms-20260801-001
Content-Type: application/jsonGrant only the permissions the external system needs. MafrexAI checks permission scopes before each request is processed.
/api/v1/property-sync/room-categoriesCreate or update room categories using stable external category IDs.
room_categories:write/api/v1/property-sync/roomsCreate or update rooms and link them to synced categories.
rooms:write/api/v1/property-sync/bookingsMirror external bookings into MafrexAI for availability and dashboard records.
bookings:write/api/v1/property-sync/checkinsPush check-in and check-out activity from an external property system.
checkins:write/api/v1/property-sync/availabilityRead MafrexAI room availability for a requested stay date range.
availability:readCategories should be synced before rooms so each room can be linked to the correct external category.
PUT https://www.mafrexai.com/api/v1/property-sync/room-categories
{
"external_source": "customer-website",
"categories": [
{
"external_category_id": "deluxe",
"name": "Deluxe Room",
"base_price": 65000,
"max_occupancy": 2,
"description": "Comfortable room for two guests.",
"amenities": ["Wi-Fi", "Air conditioning"],
"images": [],
"is_active": true
}
]
}MafrexAI upserts rooms by hotel, external source, and external room ID. If a matching room number exists, it can attach the external IDs instead of creating a duplicate room.
PUT https://www.mafrexai.com/api/v1/property-sync/rooms
{
"external_source": "customer-website",
"rooms": [
{
"external_room_id": "room-203",
"external_category_id": "deluxe",
"room_number": "203",
"room_type": "Deluxe Room",
"price": 65000,
"max_occupancy": 2,
"images": [],
"is_active": true
}
]
}Booking sync keeps MafrexAI availability accurate for reception QR bookings, dashboard reports, and hotel staff workflows.
PUT https://www.mafrexai.com/api/v1/property-sync/bookings
{
"external_source": "customer-website",
"bookings": [
{
"external_booking_id": "BK-1001",
"external_room_id": "room-203",
"guest_name": "Guest Name",
"guest_email": "guest@example.com",
"guest_phone": "+2348012345678",
"guests": 2,
"check_in_date": "2026-08-15",
"check_out_date": "2026-08-17",
"total_amount": 130000,
"status": "confirmed",
"payment_status": "paid"
}
]
}Availability excludes rooms with active overlapping bookings. The overlap rule is: existing check-in is before the requested check-out, and existing check-out is after the requested check-in.
GET https://www.mafrexai.com/api/v1/property-sync/availability?check_in_date=2026-08-15&check_out_date=2026-08-17&guests=2
Authorization: Bearer mfx_sync_your_key
Optional filters:
external_source
external_category_id
room_typeWhen a guest books through MafrexAI or the reception QR flow, MafrexAI can POST a signed callback to the external system so it can create or update the booking in its own database.
POST https://customer-site.com/api/mafrexai/booking-callback
Content-Type: application/json
X-MafrexAI-Event: booking.confirmed
X-MafrexAI-Client: property-sync-client-uuid
X-MafrexAI-Delivery: delivery-uuid
X-MafrexAI-Signature: lowercase_hex_hmac_sha256
{
"event": "booking.confirmed",
"created_at": "2026-08-01T10:30:00.000Z",
"hotel_id": "uuid",
"booking": {
"id": "uuid",
"booking_reference": "MF-ABC123",
"confirmation_code": "A1B2C3D4",
"guest_name": "Guest Name",
"guest_email": "guest@example.com",
"guest_phone": "+2348012345678",
"guests": 2,
"check_in_date": "2026-08-15",
"check_out_date": "2026-08-17",
"total_amount": 130000,
"status": "confirmed",
"payment_status": "paid",
"payment_method": "paystack",
"paystack_reference": "MF-ABC123"
},
"room": {
"id": "uuid",
"room_number": "203",
"room_type": "Deluxe Room",
"external_source": "customer-website",
"external_room_id": "room-203",
"external_category_id": "deluxe"
}
}The signature is the lowercase hex digest of HMAC-SHA256 over the exact raw UTF-8 JSON body. There is no sha256= prefix. The callback secret is separate from the mfx_sync_... key.
import crypto from "crypto";
export function verifyMafrexAISignature(
rawBody: string,
receivedSignature: string,
callbackSecret: string
) {
const expected = crypto
.createHmac("sha256", callbackSecret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(receivedSignature)
);
}Callback receivers should be duplicate-safe. MafrexAI records delivery status and lets hotel operators retry failed deliveries from the dashboard.
Read the raw request body before parsing JSON.
Verify X-MafrexAI-Signature when a callback secret is configured.
Treat X-MafrexAI-Delivery as the duplicate-safe delivery identifier.
Return 2xx only after the booking is safely recorded.
Return the same 2xx response for duplicate delivery IDs that were already processed.
Status handling
Use 2xx for delivered. Use 400, 401, 403, 409, or 422 for terminal validation conflicts that need manual review. Use 429, 500, 502, 503, or 504 when the receiver is temporarily unavailable and should be retried from the MafrexAI dashboard.
Use MafrexPay payment orders when the external website should send a guest to Paystack checkout and record the paid booking in MafrexAI.