Skip to content

Booking API

Show live availability and prices from Zitlin on your own website, then finish the booking in one of two ways:

This page is for the developer building the website. If you just want a booking page without building anything, use the booking engine on its own.

Base URL https://server.zitlin.com/pub/api/v1
Format JSON. Dates are YYYY-MM-DD, money is a string such as "1000.00"
Schema GET /openapi.json (OpenAPI, no key needed)

Getting a key

Write to support, and name the property and how the website will take bookings. Zitlin issues a key, which is shown once and can't be retrieved later. Send it on every call:

Authorization: Bearer zk_...

The key identifies the property, so no property id appears in any URL. There are two kinds:

Key Can use For a website that
Read-only /availability/ and /quote/ Shows prices and sends guests to the booking page
Booking Everything on this page Takes payment itself

A read-only key gets a 403 from every /bookings/ endpoint. If the website later starts taking payment, support can upgrade the same key.

Call this API from your server only

Keep either kind of key out of browser and app code. Browsers are blocked from calling this API directly. If a key leaks, ask support to revoke it and issue a new one.

Test on a test property

Ask for a key on a test property while you build. A key for a live hotel creates real bookings that the hotel will see and prepare for.


Sending guests to the booking page

Your website needs only a read-only key, GET /availability/, GET /quote/ or both, and no payment setup of its own.

Once the guest has chosen, send them to one of these links. Neither link needs a key, and each opens in the guest's browser.

Where Field Use it when
/quote/ book_url on each room type You have already quoted the stay. It is ready to use
/availability/ book_url_template Your Book button sits on the calendar. Fill in the stay yourself

Fill in the template's {check_in}, {check_out}, {adults}, {children} and {room_type_id}:

https://server.zitlin.com/pub/engine/your-hotel/?checkin={check_in}&checkout={check_out}&adults={adults}&children={children}&room={room_type_id}&src=website

The guest lands on the booking page with their dates and party filled in and the chosen room listed first. They pick a rate, tap Book, enter their details and pay any deposit there.

These are ordinary booking-engine bookings:

  • They arrive On hold on the calendar for the hotel to accept, and any deposit follows the hotel's booking engine settings.
  • Zitlin emails the guest and the hotel, so your website sends nothing.
  • POST /bookings/ and GET /bookings/{reference}/ don't apply, because your website has no reference for them.

Both fields are null when the booking page can't take the booking: the hotel's booking engine is off or needs its payment setup finished, or the property can't take more bookings this month. book_url is also null for a room type with nothing left. Hide the Book button when you get null.

Without the API

If your website doesn't need to show live prices, you don't need a key or any of the endpoints on this page. Add a date picker and open the same link with the guest's dates:

https://server.zitlin.com/pub/engine/your-hotel/?checkin=2026-12-01&checkout=2026-12-03&adults=2&children=0&src=website

The guest sees the prices and available rooms on the booking page. Leave out room, or add it if you already know the room type's id.

How a paid booking works

For a website that charges the guest itself. This needs a booking key.

Step Call Why
1. Show the calendar GET /availability/ Availability and nightly prices
2. Guest picks dates GET /quote/ Rates and exact totals for that stay
3. Guest enters their details
4. Just before charging POST /bookings/check/ Would this booking go through?
5. Charge the guest Your gateway
6. Record the booking POST /bookings/ Creates the booking in Zitlin

Your website doesn't need the hotel's booking engine switched on for this.

Don't skip step 4. If it returns available: false or an error, don't charge the guest. Only step 6 happens after the money has moved, so step 4 is your last chance to avoid a refund.

Rules to build around

A paid booking is accepted even if the room has gone. If the last room sells between steps 4 and 6, POST /bookings/ still creates the booking and returns overbooked: true. The booking has no room assigned, is tagged Overbooked, and the hotel is emailed so they can arrange a room or contact the guest.

A 409 or 422 from POST /bookings/ means the guest has no booking. If you have already charged them, refund them.

reference must be unique for each order. Use your order id. Sending the same reference again returns the original booking with a 200 and creates nothing, so retry freely after a timeout or a 5xx. The rest of the request isn't compared, so reusing a reference for a different order returns the old booking.

One room per call. For a two-room order, make two calls with two references, such as order_123-1 and order_123-2.

A payment is required. payment.amount must be above zero and no more than the total. It can be a partial prepayment, and the rest is the balance due at the property.

Show levies to the guest. Charges like Green Tax or a city tax are not in any total. They are billed at the property, and listed in levies_due_at_property.

You email the guest. Zitlin sends the guest nothing. Send your own confirmation, and include status_url if you want them to have a live status page.

Cancellations and refunds stay with the hotel. A cancelled booking shows as cancelled on GET /bookings/{reference}/. Zitlin doesn't refund the guest or notify your website.

Rounding

total is what you should charge. The hotel's invoice can differ from it by up to a cent per night when a night's tax isn't a whole number of cents, such as a price with decimals or compounding taxes. A fully prepaid guest can therefore show a balance of a few cents on the invoice.


GET /availability/

The calendar: every room type sold online, night by night.

Parameter Required
date_from Yes First night
date_to Yes Last night, inclusive. At most 92 nights per call
adults No Party size to price, 1–20. Default 2
{
  "currency": "INR",
  "check_in_time": "14:00",
  "check_out_time": "11:00",
  "accepting_bookings": true,
  "book_url_template": "https://server.zitlin.com/pub/engine/your-hotel/?checkin={check_in}&checkout={check_out}&adults={adults}&children={children}&room={room_type_id}&src=website",
  "room_types": [
    {
      "room_type_id": 12,
      "name": "Deluxe",
      "photo_url": "https://...",
      "max_occupancy": 3,
      "nights": [
        {
          "date": "2026-12-01",
          "available": 4,
          "open": true,
          "closed_to_arrival": false,
          "closed_to_departure": false,
          "min_stay": 1,
          "max_stay": 30,
          "price": "5500.00"
        }
      ]
    }
  ]
}
Field
accepting_bookings If false, the property can't take new bookings this month. Don't offer booking
book_url_template The link to the booking page, or null if it can't take the booking
available Rooms left that night
open False if this party can't have the room, or the night is past the booking window
closed_to_arrival, closed_to_departure The guest can't check in, or check out, on this date
min_stay, max_stay Nights allowed for a stay arriving on this date
price That night's price including tax, at the room type's own rate. null if this party can't have the room

A night can be sold only if available is above 0 and open is true. Dates outside the bookable window are left out, and room_types is empty if nothing is left.

Cache this for about a minute rather than calling it on every page view. /quote/ and /bookings/check/ give the final answer.

GET /quote/

The rates and exact totals for one stay.

Parameter Required
check_in, check_out Yes The stay
adults No 1–20. Default 2
children No 0–6. Default 0. Children don't change the price
{
  "currency": "INR",
  "accepting_bookings": true,
  "room_types": [
    {
      "room_type_id": 12,
      "name": "Deluxe",
      "photo_url": "https://...",
      "max_occupancy": 3,
      "available": 4,
      "rates": [
        {
          "rate_plan_id": null,
          "name": "Room only",
          "meal_plan": "Room only",
          "total": "11000.00",
          "tax": "1000.00"
        },
        {
          "rate_plan_id": 7,
          "name": "With breakfast",
          "meal_plan": "Breakfast included",
          "total": "12100.00",
          "tax": "1100.00"
        }
      ],
      "book_url": "https://server.zitlin.com/pub/engine/your-hotel/?checkin=2026-12-01&checkout=2026-12-03&adults=2&children=0&room=12&src=website"
    }
  ],
  "levies_due_at_property": [
    {"name": "Green Tax", "amount": "6.00", "per_guest": true, "per_adult": false}
  ]
}
  • total includes tax. Pass it back unchanged as expected_total.
  • rate_plan_id is null for the room type's own rate. Pass the id back if the guest picks a plan.
  • Room types the party doesn't fit are left out. A room type with nothing left has available: 0, no rates and no book_url.
  • book_url sends the guest to the booking page with this stay filled in. You can ignore it if you take payment yourself.
  • Each levy's amount is per night: per guest or per adult as flagged, or per room if neither is set.

POST /bookings/check/

Would this exact booking go through? Takes the booking body and writes nothing. Call it just before charging the guest.

{"available": true, "reason": "", "total": "11000.00"}

If available is false, reason says why, such as no rooms left or a minimum stay. Don't charge the guest. It returns the same errors as POST /bookings/.

POST /bookings/

Records a booking the guest has paid for.

{
  "reference": "order_123",
  "room_type_id": 12,
  "rate_plan_id": null,
  "check_in": "2026-12-01",
  "check_out": "2026-12-03",
  "adults": 2,
  "children": 0,
  "expected_total": "11000.00",
  "payment": {"amount": "3000.00", "currency": "INR"},
  "guest": {
    "name": "Jane Smith",
    "email": "[email protected]",
    "phone_country_code": "91",
    "phone": "98424 01726",
    "country": "IN",
    "address": "12 Lake Road",
    "city": "Jaipur",
    "state": "Rajasthan",
    "postal_code": "302001",
    "notes": "Late arrival"
  }
}
Field Required
reference Yes Your order id. Up to 100 characters, no / or control characters
room_type_id Yes From the quote
rate_plan_id No From the quote. Leave out for the room type's own rate
check_in, check_out Yes
adults Yes 1–20
children No 0–6. Default 0
expected_total Yes The total from the quote
payment.amount Yes What you charged. Above zero, no more than the total, up to 2 decimals
payment.currency Yes Must be the property's currency
guest.name Yes Up to 255 characters
guest.email Yes Up to 254 characters
guest.phone_country_code Yes Such as 91 or +1
guest.phone Yes 4–15 digits. Spaces and dashes are fine
guest.country Yes Two-letter code, such as IN
guest.address No Up to 500 characters
guest.city No Up to 200 characters
guest.state No Up to 100 characters
guest.postal_code No Up to 64 characters
guest.notes No Up to 1,000 characters. Shown to the hotel on the booking

If a guest with this email has stayed before, the booking is added to their existing record, and their saved details aren't changed.

Returns 201 for a new booking, or 200 if the reference already exists:

{
  "reference": "order_123",
  "booking_reference": "K7M2PQX",
  "folio_number": 1042,
  "status": "confirmed",
  "status_url": "https://server.zitlin.com/pub/engine/status/...",
  "total": "11000.00",
  "paid": "3000.00",
  "balance": "8000.00",
  "overbooked": false
}
Field
booking_reference The reference to give the guest
folio_number The booking number the hotel sees
status_url A page the guest can open to see their booking's status
total, paid, balance As recorded at booking. They exclude levies, and later payments or changes at the hotel aren't reflected
overbooked True if the room wasn't available when the booking arrived

GET /bookings/{reference}/

Where a booking stands now. Returns the same shape as POST /bookings/, with status as one of confirmed, on_hold, cancelled or no_show. Returns 404 for an unknown reference.


Errors

Errors look like this. Branch on the status and code, because detail is written for people and may change.

{"detail": "The price for this stay is now 12100.00.", "code": "PRICE_CHANGED"}
Status Code Meaning What to do
400 INVALID_REQUEST The body isn't valid JSON Fix the request
401 The key is wrong or revoked, or the property is inactive or restricted Write to support
403 KEY_READ_ONLY A read-only key was used on a /bookings/ endpoint Use a booking key, or write to support to upgrade this one
404 Unknown reference
409 PRICE_CHANGED The price moved, or the rate is no longer offered Quote again. If already charged, refund
422 INVALID_REQUEST Bad input or dates, wrong currency, party too large, or the room type isn't sold online Fix the request. If already charged, refund
429 Too many calls Slow down and cache

For a 422 from a badly formed field, detail is a list showing which field failed.

Limits

We apply limits to prevent abuse. If you get a 429 or expect heavy traffic, write to support for more information.