MafrexAI - Intelligent Hospitality Platform

Property Sync API

Synchronize external booking systems with MafrexAI.

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.

Key boundary

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.

Scoped credentials

Generate keys from Hotel Dashboard -> Property Sync or External Website. Copy the full secret once and store only on the server.

Safe retries

Write endpoints support Idempotency-Key so an interrupted sync can be retried without duplicate records.

Booking callbacks

MafrexAI can notify the external system when a MafrexAI-originated room booking is confirmed.

Authentication

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/json

Endpoint map

Grant only the permissions the external system needs. MafrexAI checks permission scopes before each request is processed.

MethodEndpointScope
PUT
/api/v1/property-sync/room-categories

Create or update room categories using stable external category IDs.

room_categories:write
PUT
/api/v1/property-sync/rooms

Create or update rooms and link them to synced categories.

rooms:write
PUT
/api/v1/property-sync/bookings

Mirror external bookings into MafrexAI for availability and dashboard records.

bookings:write
PUT
/api/v1/property-sync/checkins

Push check-in and check-out activity from an external property system.

checkins:write
GET
/api/v1/property-sync/availability

Read MafrexAI room availability for a requested stay date range.

availability:read

Room categories

Categories 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
    }
  ]
}

Rooms

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
    }
  ]
}

Bookings

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

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_type

Booking confirmed callback

When 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"
  }
}

Signature verification

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)
  );
}

Receiver contract

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.

Need the payment API too?

Use MafrexPay payment orders when the external website should send a guest to Paystack checkout and record the paid booking in MafrexAI.

Read MafrexPay docs