Skip to content

Reservations

Reservations are table bookings at one of the merchant’s stores. They live in the same table the POS host screen, the back office and the merchant’s own online booking page read, so a booking you create appears on the store’s reservation list straight away, and a status the host changes at the door is what your next read returns.

Every reservation belongs to a customer. Find or create the customer first, then book for them.

A Full API token includes the reservation scopes. If bookings are all your integration does, use the Reservation API instead — it is the same endpoints with a narrower bundle and no product-level gate.

MethodPathScope
GET/v1/reservationsreservations.read
GET/v1/reservations/:idreservations.read
POST/v1/reservationsreservations.write
PATCH/v1/reservations/:idreservations.write

There is no DELETE. To call a booking off, move it to cancelled — the row stays, so the merchant keeps the history.

  1. Find or create the customer. Search by mobile first — merchants match guests by phone at the door, and a duplicate splits the guest’s history.

    Terminal window
    curl -s "$API_BASE_URL/customers?mobile=%2B919845012345" \
    -H "Authorization: Bearer $ACCESS_TOKEN"

    If data is empty, create the customer and keep the returned id.

  2. Create the reservation for that customer at a store. The response gives you the new reservation id.

  3. Move it through its states as your product learns more — confirmed by the guest, seated at the door, completed when they leave, or cancelled.

  4. Read it back to show the host stand or reconcile with your own system.

Terminal window
curl -s "$API_BASE_URL/reservations" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"customerId": 5521,
"storeId": 1,
"reservationDate": "2026-10-24",
"reservationTime": "19:30",
"partySize": 4,
"occasion": "Anniversary",
"phone": "+919845012345",
"note": "Window table if possible",
"preOrderedFoods": [
{ "name": "Chocolate cake", "quantity": 1, "price": 18, "notes": "Candle, no message" }
]
}'
201 Created
{
"data": { "reservationId": 318 }
}

The create response carries only the id. Call GET /v1/reservations/:id when you need the stored row.

FieldTypeRequiredNotes
customerIdnumberyesAn existing customer id
reservationDatestringyesYYYY-MM-DD. Must be a real date — 2026-02-30 is rejected
reservationTimestringyesHH:mm or HH:mm:ss, 24-hour, between 00:00 and 23:59:59
partySizenumberyesNumber of guests, at least 1
storeIdnumbersee belowThe store the table is at. Always send it
durationMinutesnumberno15–600. Defaults to the store’s reservation duration, else 120
statusstringnoDefaults to confirmed when the store auto-accepts bookings, else pending. See lifecycle
occasionstringnoFree text up to 100 characters — “Birthday”, “Anniversary”, “Business”
notestringnoNote for front-of-house staff, up to 500 characters
phonestringnoContact for this booking, up to 20 characters
emailstringnoUp to 120 characters
addressstringnoUp to 300 characters
customerPreferencesstringnoAllergies, seating preferences — up to 500 characters
customerPhotoUrlstringnoPhoto the host can match at the door, up to 500 characters
preOrderedFoodsarraynoDishes ordered with the booking: { name, quantity, price, notes } per line
extraobjectnoAccepted for compatibility; not stored

Unknown properties are rejected with 400 — guests instead of partySize fails loudly rather than booking a table for nobody.

reservationDate and reservationTime are the wall-clock time at the store — what the guest booked and what the host reads — not an instant. Send 19:30 for a 7:30 pm table regardless of where your servers run, and do not convert to UTC. “Today” and “in the past” are judged on the store’s clock too.

phone, email and address on the booking are a snapshot for this reservation — useful for a guest booking on someone else’s behalf. When you leave them out, reads fall back to the customer record’s mobile, email and address.

Merchants can set reservation rules per store in the back office. A rule the merchant has not set is not enforced — with no rules at all, any number of overlapping bookings is allowed.

RuleCheckedErrorStatus
Reservations switched off for the storecreatereservations.disabled400
Date before the store’s todaycreatereservations.date_in_past400
Minimum party sizecreate, or an update that changes partySizereservations.party_too_small400
Maximum party sizecreate, or an update that changes partySizereservations.party_too_large400
How many days ahead a booking may be madecreate, or an update that moves the date or timereservations.too_far_ahead400
Minimum notice before the booking startscreate, or an update that moves the date or timereservations.notice_too_short400
Maximum bookings per daywhen the booking holds a tablereservations.day_full409
Maximum overlapping bookingswhen the booking holds a tablereservations.slot_full409
Seat capacity across overlapping bookingswhen the booking holds a tablereservations.seats_full409
The same customer already has a booking at that exact date and time, at any storecreate, or an update that moves the bookingreservations.customer_already_has_reservation400

pending, confirmed and seated bookings hold a table; completed and cancelled ones do not. Two bookings overlap when their time windows — start plus duration, widened by any buffer the merchant set before and after — intersect. Bookings that merely touch, one ending at 21:30 and the next starting at 21:30, do not overlap.

The limit that was hit comes back in params, so you can explain it to the guest:

400 Bad Request
{
"status": "error",
"statusCode": 400,
"timestamp": "2026-10-15T06:05:21.402Z",
"path": "/v1/reservations",
"message": "Party size cannot be more than 20.",
"code": "reservations.party_too_large",
"params": { "max": 20 },
"correlationId": "c1d7a0e2-5b4f-4f0e-9a51-0f6b2a8c4e19"
}
Codeparams
reservations.date_in_pastdate
reservations.party_too_smallmin
reservations.party_too_largemax
reservations.too_far_aheaddays
reservations.notice_too_shortminutes
reservations.day_full, reservations.slot_fullmax
reservations.seats_fullcapacity, available
FromAllowed next states
pendingconfirmed, cancelled
confirmedseated, completed, cancelled
seatedcompleted, cancelled
completed—
cancelled—

completed and cancelled are final: nothing moves out of them, and a completed booking cannot be cancelled. Sending the status a booking already has is accepted. Any other move is refused:

409 Conflict
{
"status": "error",
"statusCode": 409,
"timestamp": "2026-10-15T06:05:05.982Z",
"path": "/v1/reservations/318",
"message": "A seated reservation cannot be changed to pending.",
"code": "reservations.invalid_status_transition",
"params": { "from": "seated", "to": "pending" },
"correlationId": "57cc9574-36d2-43d9-a55a-14c4bf1ec80a"
}

The host can change a status at the store at any time. Read the booking before you act on its state, and treat reservations.invalid_status_transition as “someone got there first”, not as a bug in your request.

Terminal window
curl -s -X PATCH "$API_BASE_URL/reservations/318" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "status": "confirmed" }'
200 OK
{
"data": { "reservationId": 318 }
}

PATCH takes the same fields as create, all optional. Send only what changes — fields you leave out are untouched, and null clears a text field such as note.

Moving a booking that holds a table — a new date, time, duration, party size, store or customer — re-runs the booking rules against the store’s other bookings. The window rules (days ahead, minimum notice) run only when the date or time moves, and the party-size rules only when partySize changes, so a booking made before the merchant tightened a limit can still have its note edited.

Move a booking to 8 pm for five
curl -s -X PATCH "$API_BASE_URL/reservations/318" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "reservationTime": "20:00", "partySize": 5 }'
Terminal window
curl -s "$API_BASE_URL/reservations/318" \
-H "Authorization: Bearer $ACCESS_TOKEN"
200 OK
{
"data": {
"ID": 318,
"CustomerId": 5521,
"CustomerName": "Priya Nair",
"StoreId": 1,
"StoreName": "Brigade Road",
"ReservationDate": "2026-10-24",
"ReservationTime": "19:30:00",
"PartySize": 4,
"DrationMinutes": 120,
"Status": "pending",
"Occasion": "Anniversary",
"Note": "Window table if possible",
"Phone": "+919845012345",
"Email": "priya@example.com",
"Address": null,
"CustomerPreferences": null,
"CustomerPhotoUrl": null,
"PreOrderedFoods": [
{ "name": "Chocolate cake", "quantity": 1, "price": 18, "notes": "Candle, no message" }
],
"Channel": 0,
"ChannelReservationId": null,
"Source": null,
"CreatedBy": 1,
"UpdatedBy": null,
"EntryDate": "2026-10-15 11:34:47",
"LastUpdate": "2026-10-15 11:34:47"
}
}
FieldNotes
IDReservation id
CustomerId, CustomerNameThe customer, with their name joined in
StoreId, StoreNameThe store, with its name joined in. StoreId is null on a booking made without a store
ReservationDate, ReservationTimeStore wall clock, YYYY-MM-DD and HH:mm:ss
PartySizeNumber of guests
DrationMinutesDuration in minutes
Statuspending, confirmed, seated, completed or cancelled
Occasion, Note, CustomerPreferences, CustomerPhotoUrlAs sent on create or update
Phone, Email, AddressThe booking’s own contact details, else the customer record’s
PreOrderedFoodsAlways an array; [] when nothing was pre-ordered
Sourceonline for a guest who booked through the merchant’s own online booking page, quiqqy for a booking from the QUIQQY channel, else null
Channel, ChannelReservationIdThe external channel and its booking id, for channel bookings
CreatedBy, UpdatedByMerchant employee ids. Single-reservation reads only
EntryDate, LastUpdateYYYY-MM-DD HH:mm:ss
Terminal window
curl -s "$API_BASE_URL/reservations?storeId=1&fromDate=2026-10-24&toDate=2026-10-24&order=asc" \
-H "Authorization: Bearer $ACCESS_TOKEN"
{
"data": [ /* reservation rows, as above */ ],
"meta": { "page": 1, "limit": 10, "total": 7 }
}
ParameterTypeNotes
storeIdnumberOne store
statusstringpending, confirmed, seated, completed or cancelled
customerIdnumberBookings of one customer
fromDate / toDatestringReservation date window, YYYY-MM-DD, both ends inclusive
searchstringContains-match on the customer’s name, mobile and email, and the booking’s phone and email
orderasc | descBy reservation date, then time. Default desc
page, limitnumberStandard paging; limit defaults to 10, maximum 100

The list is always ordered by reservation date and time — sort is not accepted on this endpoint and returns 400. List rows carry everything a single read does except CreatedBy and UpdatedBy, so a host screen needs one call, not one per booking.

CodeStatusMeaningFix
reservations.not_found404No reservation with that id in this merchantCheck the id returned at creation
reservations.invalid_status_transition409The lifecycle does not allow that moveRead the booking; it may have moved at the store
reservations.customer_already_has_reservation400The customer already has a booking at that exact date and timeUpdate the existing booking instead
reservations.disabled400The merchant switched reservations off for the storeDo not offer booking at that store
reservations.date_in_past400The date is before the store’s todaySend a date on or after today, store time
reservations.party_too_small, reservations.party_too_large400Outside the store’s party-size limitsShow params.min / params.max to the guest
reservations.too_far_ahead400Beyond the store’s booking horizonShow params.days
reservations.notice_too_short400Too close to the start timeShow params.minutes
reservations.day_full, reservations.slot_full, reservations.seats_full409The store is fully booked for that day or timeOffer another time
reservations.busy409Another booking for the same store was being saved at that momentRetry once after a short pause
—503Reservations are not set up for this merchantContact the merchant

Validation failures — a missing required field, 2026-02-30, 25:00, a duration under 15, an unknown property — are 400 with no code; the message names the fields. See errors.