Skip to content

Booking flow

CBMS booking is always two-phase:

availability  →  hold  →  (you collect payment)  →  confirm

There is no single “book this slot” endpoint. If you skip hold, you are not integrated.

1. Availability is a hint

http
GET /api/v1/slots/availability?venue_id=<uuid>&date=2026-09-20&resource_id=badminton-court-1
x-api-key: <your-api-key>

is_available: true means “probably free when we looked.” Another channel can hold it before you do. Treat the list as a catalogue; hold is the mutex.

Book the slot_start / duration that availability returned. Do not invent windows.

2. Hold — this is the reservation

http
POST /api/v1/bookings/hold
Content-Type: application/json
x-api-key: <your-api-key>

{
  "venue_id": "a0000000-0000-4000-8000-000000000001",
  "resource_id": "badminton-court-1",
  "slot_start": "2026-09-20T18:00:00.000Z",
  "slot_duration_minutes": 60,
  "idempotency_key": "hold-9f2a-4c1e-8b7d-1a2b3c4d5e6f"
}

Do not send partner_id. Optional customer_phone lets membership pricing apply at hold time.

201:

json
{
  "hold_id": "…",
  "slot_id": "…",
  "status": "ACTIVE",
  "hold_expiry_at": "2026-09-20T17:25:00.000Z",
  "price_rupees": 600
}

hold_expiry_at is typically ~15 minutes from now (venue-configurable). Show a countdown. After expiry the slot returns to AVAILABLE (usually within a minute). You will get hold_expired if you subscribed.

If the customer abandons checkout, release immediately:

http
POST /api/v1/partner/holds/{hold_id}/cancel
Content-Type: application/json
x-api-key: <your-api-key>

{ "idempotency_key": "cancel-hold-9f2a-…", "reason": "abandoned checkout" }

Letting it expire also works; cancel is faster for the next customer.

Hold errors you will actually hit

HTTPerrorWhat to do
400SLOT_NOT_AVAILABLEPast slot, closed day/hours, unknown resource_id, or booking-rule violation. Pick another slot.
409SLOT_NOT_AVAILABLESomeone else holds or booked it, or the window overlaps a HELD/BOOKED row. Pick another slot.
409TRANSFORMATION_CONFLICTThis court is free but a convertible sibling (e.g. the football field that occupies two box-cricket courts) is reserved. Pick another slot.
403VENUE_NOT_AUTHORIZEDThis venue is not granted to your key.
429RATE_LIMIT_EXCEEDEDHonour Retry-After.

3. You collect payment

CBMS does not charge the customer on confirm. payment_reference is an opaque string from your processor so you can correlate later.

Do not confirm until you intend the booking to exist. Confirm is the inventory commit.

4. Confirm — before hold_expiry_at

http
POST /api/v1/bookings/confirm
Content-Type: application/json
x-api-key: <your-api-key>

{
  "hold_id": "…",
  "payment_reference": "pay_example_ref",
  "customer_name": "Aarav Sharma",
  "customer_phone": "9876543210",
  "customer_email": "[email protected]",
  "idempotency_key": "confirm-9f2a-4c1e-8b7d-1a2b3c4d5e6f"
}

201:

json
{
  "booking_id": "…",
  "slot_id": "…",
  "status": "BOOKED",
  "booked_at": "2026-09-20T17:12:43.812Z",
  "price_rupees": 600
}
HTTPerrorWhat to do
404HOLD_NOT_FOUNDWrong id.
409HOLD_EXPIREDWindow passed. New hold, then confirm.
409INVALID_HOLD_STATEAlready confirmed, cancelled, or expired. Refresh the customer view.
409DOUBLE_BOOKING_ATTEMPTSlot changed between hold and confirm. Report it; should be rare.

5. Cancel or refund after confirm

See Cancellations. Each call needs its own idempotency_key, different from the hold and confirm keys.

Retries

Persist idempotency_key next to the local operation. If the HTTP call times out, retry the same body and key. Details — including the hold special case — are on Idempotency.

Start in the sandbox. Production access is granted after certification.