Skip to content

How to build: checkout and pay

Create the booking on Core Backend. Start payment on Middleware Backend. Middleware Backend confirms the booking on Core Backend after the PSP webhook, then can send email.

Re-check availability → POST booking (pending) → POST payments/initialize → PSP → webhook (Middleware Backend) → booking confirmed → emails

1. Re-check availability

Middleware Backend · winner · to implement

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/availability/check

Same body as the search page. If available < units_booked, stop.


2. Create booking (pending hold)

Core Backend · winner

POST https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/booking

http
x-api-key: {API_KEY}
Authorization: Bearer {access_token}
Content-Type: application/json

Hotel (parent = rate plan)

json
{
  "request_id": "booking-guest-001-unique",
  "meta_key": "booking_20261001_standard",
  "title_name": "ABC Hotel — Standard Room",
  "parent_entity_type": "rate_plan",
  "parent_entity_uuid": "{rate_plan_uuid}",
  "owned_by": "{guest_user_uuid}",
  "status": "pending",
  "extra_data": {
    "property_uuid": "{property_uuid}",
    "room_uuid": "{room_uuid}",
    "rate_plan_uuid": "{rate_plan_uuid}",
    "check_in": "2026-10-01",
    "check_out": "2026-10-03",
    "nights": 2,
    "units_booked": 1,
    "guest_count": 2,
    "rate_per_night_ngn": 30000,
    "total_amount_ngn": 60000,
    "currency": "NGN",
    "guest_name": "John Doe",
    "guest_email": "john@example.com",
    "guest_phone": "+2348012345678"
  }
}

Shortlet (parent = property)

json
{
  "request_id": "booking-shortlet-001",
  "meta_key": "booking_shortlet_oct2026",
  "title_name": "Luxury Shortlet — Lekki",
  "parent_entity_type": "property",
  "parent_entity_uuid": "{property_uuid}",
  "owned_by": "{guest_user_uuid}",
  "status": "pending",
  "extra_data": {
    "property_uuid": "{property_uuid}",
    "check_in": "2026-10-01",
    "check_out": "2026-10-05",
    "nights": 4,
    "units_booked": 1,
    "guest_count": 4,
    "rate_per_night_ngn": 150000,
    "total_amount_ngn": 600000,
    "currency": "NGN"
  }
}

Save data.uuid{booking_uuid}.

How to build: send owned_by = logged-in guest uuid. Core Backend must reject any other owned_by on this JWT. If that check is missing, recommend it on Core Backend path settings.


3. Start payment

Middleware Backend · winner · to implement

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/payments/initialize

http
Authorization: Bearer {access_token}
Content-Type: application/json
json
{
  "booking_uuid": "{booking_uuid}",
  "provider": "paystack",
  "amount_kobo": 6000000,
  "currency": "NGN",
  "callback_url": "https://bookdirect.ng/booking/confirmation?booking={booking_uuid}"
}

amount_kobo must match booking.extra_data.total_amount_ngn * 100. Middleware Backend:

  1. GET the booking from Core Backend (must be owned_by = JWT user, status pending)
  2. Creates/updates Core Backend payment entity
  3. Calls Paystack / Squad / Tsara
  4. Returns { authorization_url, reference, payment_uuid }

Frontend: redirect or open the PSP URL. Do not PUT booking to confirmed yourself after a client-side “success.”


4. Confirmation page

Poll the booking (guest’s own uuid only):

Core Backend · winner

GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/booking/{booking_uuid}

Show “processing” until status is confirmed (Middleware Backend webhook did this). Also:

GET https://backend-dev.bookdirect.live/public/api/v1/nellalink/smart-meta-manager/entity/payment?parent_entity_type=booking&parent_entity_uuid={booking_uuid}

Optional verify (if you have the PSP reference):

Middleware Backend · winner · to implement

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/payments/verify/{reference}


5. Emails (not a frontend PSP)

After confirm, Middleware Backend should send guest + owner mail. Frontend may also trigger:

Middleware Backend · winner · to implement

POST https://middleware-dev.bookdirect.live/api/v1/bookdirect/emails/send

json
{
  "template": "booking_confirmed_guest",
  "booking_uuid": "{booking_uuid}"
}

Do not call Resend from the browser.


Status lifecycle

StatusMeaningWho sets it
pendingHold, awaiting paymentFrontend → Core Backend
confirmedPaidMiddleware Backend after webhook
cancelledCancelledManage booking
checked_in / checked_outStayOwner / ops later

Checkout checklist

  • [ ] Availability re-check
  • [ ] POST booking pending on Core Backend
  • [ ] POST payments/initialize on Middleware Backend
  • [ ] Redirect to PSP
  • [ ] Confirmation page reads Core Backend booking — wait for confirmed
  • [ ] Do not mark confirmed from the client

API-first. Middleware Backend wins over Core Backend when both exist.