Integration
Taking reservations
Reading a venue's bookable times, sending in a booking your site took, telling the guest, following it and cancelling.
The reservation calls read the times a venue can be booked at, send in a booking your site took, and let you follow it and call it off when the guest changes their mind. Every call in this guide needs a key with the Can take reservations permission.
Warning: There is no separate test environment. Every reservation taken with a real key is a real booking: it lands on the venue's reservation list and its staff are told. Develop against a venue you run, and cancel the reservations you make.
The flow#
- Your server reads the venue's bookable times with
GET /venues/{venueId}/reservation-availability; your site shows them to the guest. - Once the guest has picked a time and typed a name and a phone number, your server sends the booking with
POST /venues/{venueId}/reservations. - The booking lands on the venue's reservation list. Depending on the venue's setting it is confirmed at once, or waits for the venue's answer.
- Your site tells the guest; Cibusy sends no text message about these reservations.
- Your site follows the reservation with webhooks or
GET /reservations/{reservationId}, and calls it off withPOST /reservations/{reservationId}/cancelif the guest changes their mind.
Bookable times#
Offer the venue's own times, not ones you made up. GET /venues/{venueId}/reservation-availability returns the venue's booking calendar a day at a time: from is the first day (the venue's today when left out) and days is how many you want (7 when left out, 14 at most).
curl "https://api.cibusy.com/public/v1/venues/3fa85f64-5717-4562-b3fc-2c963f66afa6/reservation-availability?from=2026-10-09&days=3" \
-H "X-Api-Key: $CIBUSY_API_KEY"The data of the answer, with two of its days:
{
"venueId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"reservationsEnabled": true,
"confirmsAutomatically": false,
"timeZone": "Europe/Istanbul",
"maxGuests": 20,
"minNoticeMinutes": 30,
"lastBookableDate": "2026-11-30",
"days": [
{
"date": "2026-10-09",
"state": "Open",
"slots": [
{ "startsAt": "2026-10-09T16:00:00.000Z", "time": "19:00" },
{ "startsAt": "2026-10-09T16:30:00.000Z", "time": "19:30" },
{ "startsAt": "2026-10-09T17:00:00.000Z", "time": "20:00" },
{ "startsAt": "2026-10-09T17:30:00.000Z", "time": "20:30" }
]
},
{ "date": "2026-10-11", "state": "Closed", "slots": [] }
]
}- What you show and what you send are two things. Show the guest a slot's
time: it is on the venue's own clock. When you send the booking, use the same slot'sstartsAt: it is an instant in UTC. - It is the calendar of the venue's own booking page. It is worked out by the rules a booking is held to, so a time listed here is a time the booking call accepts. Slots are half an hour apart.
- A day's state. On an
Openday,slotsholds the times still bookable. A day readsClosedwhen the venue is shut andHoursUnknownwhen it has entered no working hours for that weekday; neither has slots. A venue that seats past midnight lists those late times under the evening they belong to. - When the venue takes no bookings,
reservationsEnabledisfalseanddaysis empty. Do not show a booking button then. - The calendar does not know how full the venue is. It says when the venue seats, not how many tables are free: Cibusy does not count tables, and the venue declines a request it has no room for.
Sending the booking#
A reservation is sent with POST /venues/{venueId}/reservations:
curl -X POST "https://api.cibusy.com/public/v1/venues/3fa85f64-5717-4562-b3fc-2c963f66afa6/reservations" \
-H "X-Api-Key: $CIBUSY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"startsAt": "2026-10-09T17:00:00.000Z",
"guests": 4,
"customer": {
"name": "Ayşe Yılmaz",
"phone": "+905321112233"
},
"note": "Mümkünse cam kenarı bir masa."
}'| Field | Rule |
|---|---|
startsAt | An instant in UTC; the startsAt of a slot from the availability answer. Required. |
guests | 1 to 20. A larger party calls the venue. Required. |
customer.name | At most 100 characters. Required. |
customer.phone | In international form or the way it is written locally (+905321112233, 0532 111 22 33); at most 30 characters. Required. |
note | A note for the venue; at most 250 characters. Optional. |
The first successful answer is 201 Created, and its data is the reservation itself:
{
"id": "9b2f6c1e-3d4a-4f5b-8c7d-1e2f3a4b5c6d",
"venueId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"status": "Pending",
"startsAt": "2026-10-09T17:00:00.000Z",
"guests": 4,
"customer": { "name": "Ayşe Yılmaz", "phone": "+905321112233" },
"note": "Mümkünse cam kenarı bir masa.",
"code": "K7M2Q9XA",
"pageUrl": "https://cibusy.com/modakofte/reservation/K7M2Q9XA",
"canCancel": true,
"checkedInAt": null,
"cancelledAt": null,
"cancelledBy": null,
"cancellationReason": null,
"createdAt": "2026-10-01T09:30:00.000Z"
}- It lands where every other booking does. It shows on the venue's reservation list at the till and in the staff app, and its staff are told the way they are about a booking a guest made themselves.
- Whether it is confirmed is the venue's setting. At a venue that confirms bookings as they are made,
statuscomes backConfirmed. Otherwise it isPendinguntil somebody at the venue accepts or declines it; a request the venue has not answered by the time it was for is cancelled, withcancelledByreadingSystem.confirmsAutomaticallyin the availability answer says which to expect: choose between "your table is booked" and "your request has been sent to the venue" by it.
The venue's rules#
The venue's booking rules decide whether the time can be taken, the same ones its own booking page holds a guest to. A time taken from the availability answer passes all of them.
| Answer | When |
|---|---|
400 PUBLIC_API_RESERVATION_INVALID | The request breaks the shape rules. validationErrors names the part that is wrong by its path, such as customer.phone. |
400 TOO_MANY_GUESTS | More than 20 guests. |
400 INVALID_RESERVATION_DATE | The time has already passed. |
409 RESERVATIONS_DISABLED | The venue has switched bookings off. |
409 RESERVATION_TOO_SOON | The time is less than 30 minutes away. |
409 RESERVATION_TOO_FAR | The time is more than 60 days ahead. |
409 RESERVATION_TIME_UNAVAILABLE | The venue does not seat at that time. |
409 PUBLIC_API_RESERVATIONS_UNAVAILABLE | The venue has no active subscription. |
Telling the guest#
Cibusy sends no text message about a reservation taken through the API: not when it is taken, not when it is confirmed, and not when it is called off. Your site took the booking, and it is your site the guest expects to hear from. Everything you need for that is in every answer and on the webhook.
- Give the guest the
pageUrlof the answer, or itscode. The page on cibusy.com shows the booking and, once it is confirmed, the QR the venue scans at the door; the code is what the guest reads out if they have no screen to show. - Whoever holds either can see and cancel the booking, so give them to the guest only.
- For a reservation that waits for the venue (
Pending), you learn the outcome from thereservation.updatedevent and pass it on to the guest.
Retrying safely#
Sending a reservation needs no Idempotency-Key. A guest cannot sit at two tables at once, so a second request for the same phone number, the same venue and the same time, while the first booking still stands, is the same booking.
- If a request times out or the connection drops, send the same request again, unchanged. You get the reservation the first call made, as the venue has it now; the first answer was
201, this one is200, and the venue is not told a second time. - A repeat is answered without looking at the venue's rules again, because the booking already exists.
- A repeat is looked for among the reservations the API took. A booking the same guest made in the Cibusy app or on the venue's page never stands in for your site's.
- The reservation calls share a budget with placing orders: about 30 requests a minute per key, repeats included.
Following a reservation#
GET /reservations/{reservationId} reads a reservation as the venue has it now. GET /reservations lists the ones taken through the API, a page at a time; status picks the open ones (open, the default), the ones that are over (closed) or all of them (all). The open ones come soonest first: the next table to arrive is at the top. closed and all come latest first.
Each of a venue's keys can read the reservations taken with the venue's other keys. A booking the venue took some other way, in the Cibusy app, on its page on cibusy.com or over the phone, is never listed, and cannot be read by id either.
Rather than asking about reservations over and over, use a webhook: your server receives a reservation.updated event whenever one changes. These events arrive within about a minute, not within seconds as an order's do.
Reservation status#
status | When |
|---|---|
Pending | The venue has not answered yet. |
Confirmed | The venue accepted it, or confirms bookings as they are made. The table is expected. |
Declined | The venue said no. |
Cancelled | It was called off. cancelledBy says by whom: the guest (Customer), the venue (Venue), or the System when the venue never answered. |
Seated | The guest has arrived and was checked in at the door. |
Completed | The visit is over. |
NoShow | The venue accepted it and nobody came. |
Cancelling#
POST /reservations/{reservationId}/cancel is for a guest who changes their mind on your site. The optional reason is for the venue to read:
curl -X POST "https://api.cibusy.com/public/v1/reservations/9b2f6c1e-3d4a-4f5b-8c7d-1e2f3a4b5c6d/cancel" \
-H "X-Api-Key: $CIBUSY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "Cuma akşamı gelemiyoruz."
}'- It is the guest's cancellation. The same as one made on the reservation's page on cibusy.com:
cancelledByreadsCustomer, and the venue is told, with the reason when one was given. - When it can be cancelled. While the reservation is
PendingorConfirmed, the guest has not been checked in and its time has not come.canCancelon the reservation says so beforehand; show your cancel button by it. Otherwise the answer is409RESERVATION_NOT_CANCELLABLE. - Sending it twice is safe. Cancelling a reservation that is already cancelled, by anybody, answers
200with it as it stands.
What the API does not do#
- Change the time or the number of guests. The API does not change a reservation: cancel it and take a new one.
- Read the venue's other reservations. The API shows only the reservations it took itself; the ones the venue took in the app, on its own page or over the phone are left out.
- Pick a table. A reservation is for a time and a number of guests; the venue decides which table.