Appearance
Holds
A hold is a short reservation while you collect payment. Required before confirm.
Auth: database-backed x-api-key.
Create
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"
}idempotency_key is required. customer_phone is optional (membership price at hold time). Omit partner_id.
201: hold_id, slot_id, status: "ACTIVE", hold_expiry_at, price_rupees.
Confirm before hold_expiry_at (typically ~15 minutes).
Idempotency (hold is special)
Retrying the same key returns the original hold (201), even if the new body describes a different slot. It will not create a second ACTIVE hold. It also will not 409. Do not reuse a hold key across slots. See Idempotency.
Release
When the customer abandons checkout:
http
POST /api/v1/partner/holds/{holdId}/cancel
Content-Type: application/json
x-api-key: <your-api-key>
{ "idempotency_key": "cancel-hold-9f2a-…", "reason": "abandoned checkout" }idempotency_key is required. 200: { "message": "Hold released successfully", "hold_id": "…", "status": "CANCELLED" }.
| HTTP | error |
|---|---|
| 400 | IDEMPOTENCY_KEY_REQUIRED |
| 403 | UNAUTHORIZED — not your hold |
| 404 | HOLD_NOT_FOUND |
| 409 | INVALID_HOLD_STATE — not ACTIVE. A retry with the same cancel key after success still returns 200. |
Errors on create
Documented on Booking flow: SLOT_NOT_AVAILABLE (400 or 409), TRANSFORMATION_CONFLICT, VENUE_NOT_AUTHORIZED.