Skip to content

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#

  1. Your server reads the venue's bookable times with GET /venues/{venueId}/reservation-availability; your site shows them to the guest.
  2. 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.
  3. 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.
  4. Your site tells the guest; Cibusy sends no text message about these reservations.
  5. Your site follows the reservation with webhooks or GET /reservations/{reservationId}, and calls it off with POST /reservations/{reservationId}/cancel if 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:

JSON
{
  "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's startsAt: 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 Open day, slots holds the times still bookable. A day reads Closed when the venue is shut and HoursUnknown when 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, reservationsEnabled is false and days is 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."
  }'
FieldRule
startsAtAn instant in UTC; the startsAt of a slot from the availability answer. Required.
guests1 to 20. A larger party calls the venue. Required.
customer.nameAt most 100 characters. Required.
customer.phoneIn international form or the way it is written locally (+905321112233, 0532 111 22 33); at most 30 characters. Required.
noteA note for the venue; at most 250 characters. Optional.

The first successful answer is 201 Created, and its data is the reservation itself:

JSON
{
  "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, status comes back Confirmed. Otherwise it is Pending until somebody at the venue accepts or declines it; a request the venue has not answered by the time it was for is cancelled, with cancelledBy reading System. confirmsAutomatically in 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.

AnswerWhen
400 PUBLIC_API_RESERVATION_INVALIDThe request breaks the shape rules. validationErrors names the part that is wrong by its path, such as customer.phone.
400 TOO_MANY_GUESTSMore than 20 guests.
400 INVALID_RESERVATION_DATEThe time has already passed.
409 RESERVATIONS_DISABLEDThe venue has switched bookings off.
409 RESERVATION_TOO_SOONThe time is less than 30 minutes away.
409 RESERVATION_TOO_FARThe time is more than 60 days ahead.
409 RESERVATION_TIME_UNAVAILABLEThe venue does not seat at that time.
409 PUBLIC_API_RESERVATIONS_UNAVAILABLEThe 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 pageUrl of the answer, or its code. 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 the reservation.updated event 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 is 200, 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#

statusWhen
PendingThe venue has not answered yet.
ConfirmedThe venue accepted it, or confirms bookings as they are made. The table is expected.
DeclinedThe venue said no.
CancelledIt was called off. cancelledBy says by whom: the guest (Customer), the venue (Venue), or the System when the venue never answered.
SeatedThe guest has arrived and was checked in at the door.
CompletedThe visit is over.
NoShowThe 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: cancelledBy reads Customer, and the venue is told, with the reason when one was given.
  • When it can be cancelled. While the reservation is Pending or Confirmed, the guest has not been checked in and its time has not come. canCancel on the reservation says so beforehand; show your cancel button by it. Otherwise the answer is 409 RESERVATION_NOT_CANCELLABLE.
  • Sending it twice is safe. Cancelling a reservation that is already cancelled, by anybody, answers 200 with 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.