API reference

Every endpoint, parameter and example answer. The Test it section under each endpoint works with your sandbox key.

Account

Who the key belongs to.

get/v1/me

The key you are calling with

Response 200
{
  "organization": {
    "id": "…",
    "name": "Acme Travel",
    "status": "ACTIVE"
  },
  "livemode": true,
  "scopes": [
    "properties:read"
  ],
  "apiVersion": "2026-11-01",
  "rateLimit": {
    "perMinute": 600
  },
  "plan": {
    "key": "agency_100",
    "name": {
      "en": "Starter"
    },
    "maxSubscriptions": 100,
    "status": "ACTIVE",
    "trialEndsAt": null,
    "periodEnd": null,
    "used": 3
  }
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Catalog

The shared vocabulary: amenity keys, property and room types, places, currencies. Needs no subscription.

get/v1/amenity-categories

Amenity categories

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "key": "pool",
      "name": "Pool"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/amenities

All amenity keys

Keys are permanent and never renamed; a retired key is marked deprecated and points to replacedBy. kind is BOOL, NUM (with unit) or ENUM (with options).

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "key": "pool.private",
      "name": "Private pool",
      "kind": "BOOL",
      "category": "pool",
      "deprecated": false
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/property-types

Property types

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "key": "villa",
      "name": "Villa"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/room-types

Room types

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "key": "bedroom",
      "name": "Bedroom"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/bed-types

Bed types

Keys used in rooms[].beds[].type; sleeps is how many people one bed takes.

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "key": "double",
      "name": "Double bed",
      "sleeps": 2,
      "deprecated": false
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/geo/countries

Countries

Required scope: catalog:read

localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "id": "…",
      "iso": "TR",
      "dialCode": "90",
      "currency": "TRY",
      "name": "Turkey"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/geo/nodes

Children of a place

Walk the tree: country → region → city → district → neighbourhood. Pass a node id as geoId to GET /v1/properties to filter by it.

Required scope: catalog:read

parentquery · reqId of the parent node.
localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "id": "…",
      "type": "CITY",
      "name": "Kaş"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/currencies

Currencies

Required scope: catalog:read

Response 200
{
  "data": [
    {
      "code": "EUR",
      "name": "Euro",
      "symbol": "€",
      "minorUnit": 2
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/locales

Languages

Required scope: catalog:read

Response 200
{
  "data": [
    {
      "code": "en"
    },
    {
      "code": "tr"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Properties

Discover properties and read their listing. Calendar and prices need a subscription.

get/v1/properties

Query properties

Live properties in the network. Without a subscription you see the listing (texts, photos, rooms, amenities, capacity) with the location rounded to two decimals; with one you also see the exact address, owner contact and prices.

Required scope: properties:read

qqueryName, code or address contains.
geoIdqueryA place id from /v1/geo/*; matches that place and everything below it.
typesqueryComma-separated property type keys.
guestsquerySleeps at least this many.
bedroomsqueryAt least this many bedrooms.
bathroomsqueryAt least this many bathrooms.
amenitiesqueryComma-separated amenity keys; the property must have all of them.
subscribedquerytrue only properties you subscribe to, false only those you do not.
limitqueryPage size, at most 60 (default 25).
cursorqueryThe nextCursor of the previous page.
localequeryLanguage of names: tr or en.
Response 200
{
  "data": [
    {
      "id": "5b1c1f1e-0000-4000-8000-000000000001",
      "code": "BP-1004",
      "name": "Villa Mavi",
      "typeKey": "villa",
      "maxGuests": 8,
      "bedrooms": 4,
      "bathrooms": 3,
      "currency": "EUR",
      "city": "Kaş",
      "district": "Kalkan",
      "coverImageId": "…",
      "subscriptionMode": "DIRECT",
      "subscriptionStatus": null
    }
  ],
  "total": 42,
  "nextCursor": "Mg"
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/properties/{id}

One property

Required scope: properties:read

idpath · reqThe property id (UUID).
localequeryLanguage of names: tr or en.
Response 200
{
  "id": "5b1c1f1e-0000-4000-8000-000000000001",
  "code": "BP-1004",
  "name": "Villa Mavi",
  "typeKey": "villa",
  "currency": "EUR",
  "maxGuests": 8,
  "translations": {
    "en": {
      "title": "Sea-view villa"
    }
  },
  "rooms": [],
  "amenities": [
    {
      "key": "pool.private",
      "roomId": null,
      "value": true
    },
    {
      "key": "pool.heated",
      "roomId": null,
      "value": true,
      "feeMinor": 200000,
      "feeMode": "PER_NIGHT"
    }
  ],
  "images": [],
  "subscription": null
}

Possible errors: property_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/properties/{id}/media

Photos

Each photo comes in thumb, medium and large WebP. Fetch the URLs with the same Bearer key.

Required scope: properties:read

idpath · reqThe property id (UUID).
Response 200
{
  "data": [
    {
      "id": "…",
      "roomId": null,
      "caption": {},
      "width": 2400,
      "height": 1600,
      "urls": {
        "thumb": "https://api.cesisync.com/v1/media/…/thumb"
      }
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/media/{imageId}/{size}

A photo file

Required scope: properties:read

imageIdpath · reqPhoto id.
sizepath · reqthumb, medium or large.
Response 200
(binary WebP)
get/v1/properties/{id}/export

Download a property

Your data is yours: take a subscribed property with you as JSON, a ZIP of photos plus JSON, or CSV files for calendar and rates.

Required scope: properties:read

idpath · reqThe property id (UUID).
formatqueryjson (default), zip, calendar.csv or rates.csv.
localequeryLanguage of names: tr or en.
Response 200
(file)

Possible errors: not_subscribedformat_invalid

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Subscriptions

Ask for, and end, access to a property.

post/v1/properties/{id}/subscription

Subscribe

On a property with direct approval the subscription is ACTIVE at once. Otherwise it is REQUESTED and you get a subscription.approved or subscription.rejected event when the owner decides.

Required scope: subscriptions:write

idpath · reqThe property id (UUID).
Request
{
  "message": "We run 40 villas in Kaş."
}
Response 201
{
  "id": "7a0e0000-0000-4000-8000-000000000002",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "ACTIVE",
  "commissionBps": 1000,
  "requestedAt": "2027-01-05T09:00:00.000Z"
}

Possible errors: subscription_existsproperty_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

delete/v1/properties/{id}/subscription

Unsubscribe

Ends access. Refused with subscription_has_bookings while you have a running hold or a reservation that has not ended yet; those must run out or be cancelled first.

Required scope: subscriptions:write

idpath · reqThe property id (UUID).

Possible errors: subscription_not_foundsubscription_has_bookings

get/v1/subscriptions

Your subscriptions

Required scope: properties:read

statusqueryREQUESTED, ACTIVE, REJECTED or ENDED.
Response 200
{
  "data": [
    {
      "id": "7a0e0000-0000-4000-8000-000000000002",
      "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
      "status": "ACTIVE",
      "commissionBps": 1000,
      "requestedAt": "2027-01-05T09:00:00.000Z"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/subscriptions/{id}

One subscription

Required scope: properties:read

idpath · reqThe subscription id (UUID).
Response 200
{
  "id": "7a0e0000-0000-4000-8000-000000000002",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "ACTIVE",
  "commissionBps": 1000,
  "requestedAt": "2027-01-05T09:00:00.000Z"
}

Possible errors: subscription_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Calendar and rates

Availability, prices and quotes of subscribed properties.

get/v1/properties/{id}/calendar

Calendar

Day by day: FREE, BUSY (closed by the owner, an imported calendar or any agency; never says by whom) or MINE (your own hold or booking). A day is a night: 2027-07-01 is the night from 1 July to 2 July.

Required scope: calendar:read

idpath · reqThe property id (UUID).
fromquery · reqFirst day, YYYY-MM-DD.
toquery · reqLast day, exclusive (a stay ends on the day it departs).
Response 200
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "from": "2027-07-01",
  "to": "2027-07-03",
  "days": [
    {
      "date": "2027-07-01",
      "state": "FREE",
      "nightlyMinor": 25000,
      "minNights": 3
    },
    {
      "date": "2027-07-02",
      "state": "BUSY",
      "nightlyMinor": 25000,
      "minNights": 3
    }
  ]
}

Possible errors: not_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/properties/{id}/calendar.ics

Calendar as iCal

Closed nights as an RFC 5545 feed for software that only speaks iCal. Names and details are never included.

Required scope: calendar:read

idpath · reqThe property id (UUID).
Response 200
BEGIN:VCALENDAR…

Possible errors: not_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/properties/{id}/rates

Rates

Price periods overlapping the range, with minimum stay and allowed arrival weekdays (checkinDays, 0 = Sunday), plus cleaning, deposit and extra-guest terms. Amounts are integers in minor units (cents) of currency.

Required scope: rates:read

idpath · reqThe property id (UUID).
fromquery · reqFirst day, YYYY-MM-DD.
toquery · reqLast day, exclusive (a stay ends on the day it departs).
Response 200
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "currency": "EUR",
  "baseNightlyMinor": 20000,
  "minNightsDefault": 2,
  "cleaningFeeMinor": 5000,
  "depositMinor": 20000,
  "periods": [
    {
      "start": "2027-06-15",
      "end": "2027-09-15",
      "nightlyMinor": 30000,
      "minNights": 3,
      "checkinDays": [
        6
      ],
      "label": "High season"
    }
  ]
}

Possible errors: not_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/properties/{id}/availability

Availability and price for dates

Is the stay free, and what does it cost? quote lists every night, cleaning and extra-guest fees, and violations for any rule it breaks (min_nights, checkin_day_not_allowed, too_many_guests, no_rate). bookable is true only when it is free and breaks no rule. extraOptions lists the property's paid amenities with what each would cost for this stay (amountMinor); pass the ones the guest wants in extras and they appear in quote.extras and in quote.totalMinor.

Required scope: rates:read

idpath · reqThe property id (UUID).
checkInquery · reqArrival date.
checkOutquery · reqDeparture date.
guestsqueryNumber of guests (default 1).
extrasqueryPaid amenities to quote, comma separated: key for a property-wide amenity, key@roomId for one in a room.
Response 200
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "available": true,
  "bookable": true,
  "holdHoursMax": 72,
  "quote": {
    "currency": "EUR",
    "checkIn": "2027-07-10",
    "checkOut": "2027-07-14",
    "accommodationMinor": 100000,
    "cleaningMinor": 5000,
    "extraGuestsMinor": 0,
    "totalMinor": 105000,
    "depositMinor": 20000,
    "violations": [],
    "bookable": true,
    "nights": [
      {
        "date": "2027-07-10",
        "amountMinor": 25000
      }
    ]
  }
}

Possible errors: not_subscribeddates_invalid

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/availability/search

Search availability across properties

Checks the same stay against up to 50 subscribed properties at once (all of yours when propertyIds is left out).

Required scope: rates:read

Request
{
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "propertyIds": [
    "5b1c1f1e-0000-4000-8000-000000000001"
  ]
}
Response 200
{
  "data": [
    {
      "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
      "available": true,
      "bookable": true,
      "quote": {
        "totalMinor": 105000
      }
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Holds and reservations

Hold nights, book them, change or cancel. Booking is instant: the dates close for every subscriber.

post/v1/holds

Place a hold

Pass extras ([{ "key": "pool.heated" }], with roomId for an amenity of a room) for the paid amenities the guest wants: their price is added to the total and they are stored on the hold, shown to the owner, and returned in extras here and in hold.created. Takes the nights off the calendar for everyone while the guest decides or pays, for up to the time the owner allows (holdMinutesMax of the property; you may ask for less with holdMinutes or holdHours). holdRef is your number for this hold or request and is required. Confirm the hold before it ends, or it falls away on its own, the nights open again and you get hold.expired. Send an Idempotency-Key header so a retry never creates a second hold.

Required scope: reservations:write

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "holdHours": 24,
  "holdRef": "TALEP-1042"
}
Response 201
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "HOLD",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000,
  "holdRef": "TALEP-1042",
  "holdExpiresAt": "2027-06-01T12:00:00.000Z"
}

Possible errors: hold_ref_requiredextra_unknowndates_unavailablequeue_prioritystay_rules_violatednot_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/holds/{id}

One hold

Poll this (every 5 seconds is fine) if you would rather not wait for a webhook: status is HOLD while it runs, CONFIRMED once converted, EXPIRED or CANCELLED otherwise; holdExpiresAt is when it ends.

Required scope: reservations:read

idpath · reqThe hold id (UUID).
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "HOLD",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000,
  "holdExpiresAt": "2027-06-01T12:00:00.000Z"
}

Possible errors: reservation_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/holds/{id}/confirm

Confirm a hold

Turns the hold into a reservation once the guest has paid. externalRef is your reservation number and is required here (unless the hold already has one).

Required scope: reservations:write

idpath · reqThe hold id (UUID).
Request
{
  "externalRef": "REZ-2027-0042"
}
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CONFIRMED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000,
  "holdRef": "TALEP-1042"
}

Possible errors: external_ref_requiredhold_expirednot_a_hold

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/holds/{id}/extend

Ask for more time

Adds up to the owner's hold limit (minutes, default: the full limit; more is refused with 400 extension_too_long) to a running hold, at most three times and only in its last five minutes (409 extension_too_early before that). After the third extension the hold simply runs out and you place a new one, and only while no other agency is queued for the same nights. The answer is the updated hold with its new holdExpiresAt; you also get hold.extended. If someone is waiting you get 409 queue_waiting and the hold simply runs out.

Required scope: reservations:write

idpath · reqThe hold id (UUID).
Request
{
  "minutes": 15
}
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "HOLD",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000,
  "extensionCount": 1,
  "holdExpiresAt": "2027-06-01T12:15:00.000Z"
}

Possible errors: extension_too_earlyextension_too_longextension_limitqueue_waitinghold_expirednot_a_hold

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/waitlist

Your queue entries

Required scope: reservations:read

Response 200
{
  "data": [
    {
      "id": "…",
      "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
      "checkIn": "2027-07-10",
      "checkOut": "2027-07-14",
      "guests": 4,
      "holdRef": "TALEP-1043",
      "status": "WAITING",
      "priorityUntil": null
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/waitlist

Queue for held nights

When the nights you want are held by someone else, queue for them instead of polling. The first agency in line gets waitlist.available when the nights free up and five minutes (priorityUntil) during which only it can place a hold on them; if it does not, the next one is told. Queueing while the nights are free answers 409 dates_available: just place the hold.

Required scope: reservations:write

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "holdRef": "TALEP-1043"
}
Response 201
{
  "id": "…",
  "status": "WAITING",
  "ahead": 0
}

Possible errors: hold_ref_requireddates_availablewaitlist_fullnot_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

delete/v1/waitlist/{id}

Leave the queue

Required scope: reservations:write

idpath · reqThe entry id (UUID).
Response 204
null

Possible errors: waitlist_entry_not_found

delete/v1/holds/{id}

Release a hold

Required scope: reservations:write

idpath · reqThe hold id (UUID).
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CANCELLED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000
}

Possible errors: not_a_hold

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/reservations

Send a reservation

Paid amenities the guest wants go in extras (see extraOptions of the availability answer); they are added to the total, stored on the reservation and sent in reservation.confirmed. externalRef is your reservation number in your own system and is required. Books the stay and closes the nights for every subscriber within seconds (they get calendar.updated). If the nights were taken in the meantime the answer is 409 dates_unavailable; if the stay breaks a rule (min_nights …) it is 422 stay_rules_violated with the reasons. Amounts are quoted from the owner's rates at booking time and stored with the booking. Send an Idempotency-Key header: a retry with the same key returns the first answer instead of booking twice.

Required scope: reservations:write

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "notes": "Late arrival"
}
Response 201
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CONFIRMED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000
}

Possible errors: external_ref_requiredextra_unknowndates_unavailablequeue_prioritystay_rules_violatednot_subscribed

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/reservations

List reservations

Required scope: reservations:read

statusqueryHOLD, CONFIRMED, CANCELLED or EXPIRED.
propertyIdqueryOnly this property.
limitqueryAt most 500.
Response 200
{
  "data": [
    {
      "id": "0d6f6e0a-0000-4000-8000-000000000009",
      "code": "R-100231",
      "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
      "status": "CONFIRMED",
      "checkIn": "2027-07-10",
      "checkOut": "2027-07-14",
      "guests": 4,
      "guestName": "Ali Veli",
      "externalRef": "PMS-1042",
      "currency": "EUR",
      "totalMinor": 100000
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/reservations/{id}

One reservation

Required scope: reservations:read

idpath · reqThe reservation id (UUID).
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CONFIRMED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000
}

Possible errors: reservation_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

patch/v1/reservations/{id}

Change a reservation

New dates or guest count are quoted and checked again (your own nights do not count as taken); the nights move atomically. Details (guestName, externalRef, notes) change without any check.

Required scope: reservations:write

idpath · reqThe reservation id (UUID).
Request
{
  "checkOut": "2027-07-15",
  "guests": 5
}
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CONFIRMED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000
}

Possible errors: extra_unknowndates_unavailablestay_rules_violatedreservation_not_active

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/reservations/{id}/cancel

Send a cancellation

Cancels the booking and reopens the nights for every subscriber. An owner may also cancel (with a reason): you then get reservation.cancelled with by: "owner".

Required scope: reservations:write

idpath · reqThe reservation id (UUID).
Request
{
  "reason": "Guest cancelled"
}
Response 200
{
  "id": "0d6f6e0a-0000-4000-8000-000000000009",
  "code": "R-100231",
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "status": "CANCELLED",
  "checkIn": "2027-07-10",
  "checkOut": "2027-07-14",
  "guests": 4,
  "guestName": "Ali Veli",
  "externalRef": "PMS-1042",
  "currency": "EUR",
  "totalMinor": 100000,
  "cancelledBy": "AGENCY"
}

Possible errors: reservation_not_active

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Events

Everything that happened to your properties, in order. The same events your webhooks carry.

get/v1/events

Event log

Every event about your subscribed properties and your own bookings, oldest first. Keep the id of the last event you processed and pass it as after to continue; each property also numbers its events (property_seq 1, 2, 3…), so a gap tells you a webhook was missed.

Required scope: events:read

afterqueryReturn events after this id (evt_123 or 123).
propertyIdqueryOnly this property.
typequeryOnly this event type.
limitqueryAt most 500 (default 100).
Response 200
{
  "data": [
    {
      "id": "evt_981",
      "type": "calendar.updated",
      "created_at": "2027-06-01T10:00:00.000Z",
      "livemode": true,
      "api_version": "2026-11-01",
      "property_id": "5b1c1f1e-0000-4000-8000-000000000001",
      "property_seq": 14,
      "data": {
        "closed": [
          {
            "start": "2027-07-10",
            "end": "2027-07-14"
          }
        ],
        "opened": [],
        "source": "agency"
      }
    }
  ],
  "next_after": "evt_981",
  "has_more": false
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/events/{id}

One event

Required scope: events:read

idpath · reqEvent id, evt_….
Response 200
{
  "id": "evt_981",
  "type": "calendar.updated"
}

Possible errors: event_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Webhooks

Manage endpoints and look at deliveries.

get/v1/webhook-endpoints

List endpoints

Required scope: webhooks:manage

Response 200
{
  "data": [
    {
      "id": "…",
      "url": "https://example.com/hooks/bp",
      "events": null,
      "livemode": true,
      "active": true,
      "consecutiveFailures": 0
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/webhook-endpoints

Add an endpoint

The signing secret (whsec_…) is in this answer and only this answer. Leave events out to receive every event type. Addresses must be public https (http is allowed outside production).

Required scope: webhooks:manage

Request
{
  "url": "https://example.com/hooks/bp",
  "description": "PMS",
  "events": [
    "calendar.updated",
    "reservation.cancelled"
  ]
}
Response 201
{
  "id": "…",
  "url": "https://example.com/hooks/bp",
  "secret": "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw"
}

Possible errors: url_invalidurl_not_publicevent_type_invalidtoo_many_endpoints

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

patch/v1/webhook-endpoints/{id}

Change an endpoint

Set active: true to switch a disabled endpoint back on (the failure count is reset).

Required scope: webhooks:manage

idpath · reqThe endpoint id (UUID).
Request
{
  "active": true
}
Response 200
{
  "id": "…",
  "active": true
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

delete/v1/webhook-endpoints/{id}

Delete an endpoint

Required scope: webhooks:manage

idpath · reqThe endpoint id (UUID).
post/v1/webhook-endpoints/{id}/test

Send a test event

Sends a ping event now, signed like the real ones, and returns what your server answered. Nothing is stored or retried.

Required scope: webhooks:manage

idpath · reqThe endpoint id (UUID).
Response 200
{
  "ok": true,
  "status": 200,
  "ms": 84,
  "response": "ok"
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/webhook-endpoints/{id}/rotate-secret

Rotate the secret

Returns a new secret. The old one keeps signing alongside it for 24 hours (the signature header carries both), so you can switch without losing events.

Required scope: webhooks:manage

idpath · reqThe endpoint id (UUID).
Response 200
{
  "secret": "whsec_…"
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

get/v1/webhook-deliveries

Delivery log

Required scope: webhooks:manage

endpointIdqueryOnly this endpoint.
statusqueryPENDING, SUCCESS or FAILED.
limitqueryAt most 200.
beforequeryOnly deliveries created before this timestamp (for paging).
Response 200
{
  "data": [
    {
      "id": "…",
      "endpointId": "…",
      "status": "SUCCESS",
      "attempts": 1,
      "lastStatusCode": 200,
      "eventId": "evt_981",
      "eventType": "calendar.updated",
      "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
      "propertySeq": 14
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/webhook-deliveries/{id}/retry

Send a delivery again

Required scope: webhooks:manage

idpath · reqThe delivery id (UUID).
Response 202
{
  "status": "queued"
}

Possible errors: delivery_not_found

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

Sandbox

Test-key only: reset the sample data and simulate what owners and other agencies do.

post/v1/sandbox/resetsandbox only

Reset the sandbox

Deletes your sandbox reservations and properties and creates the three sample properties again.

Response 200
{
  "status": "reset"
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/owner-blocksandbox only

The owner closes dates

Triggers calendar.updated with source: "owner".

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "from": "2027-02-01",
  "to": "2027-02-05"
}
Response 200
{
  "closed": [
    {
      "start": "2027-02-01",
      "end": "2027-02-05"
    }
  ]
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/owner-unblocksandbox only

The owner reopens dates

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "from": "2027-02-01",
  "to": "2027-02-05"
}
Response 200
{
  "opened": [],
  "stillClosed": []
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/other-agency-bookingsandbox only

Another agency books

Closes the dates and triggers calendar.updated with source: "agency", exactly what you receive when a competitor books a shared property.

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "from": "2027-02-10",
  "to": "2027-02-12"
}
Response 200
{
  "ok": true
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/price-changesandbox only

The owner changes the price

Triggers rates.updated.

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "from": "2027-02-20",
  "to": "2027-02-25",
  "nightlyMinor": 29900
}
Response 200
{
  "ok": true
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/property-updatesandbox only

The owner edits the listing

Triggers property.updated. name really renames the sandbox property.

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
  "name": "Villa Mavi Deluxe"
}
Response 200
{
  "ok": true
}
Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/subscription-approvesandbox only

The owner approves your request

For a property you subscribed to that waits for approval. Triggers subscription.approved.

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001"
}
Response 200
{
  "ok": true
}

Possible errors: no_pending_request

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.

post/v1/sandbox/simulate/subscription-revokesandbox only

The owner ends your subscription

Triggers subscription.revoked and releases your holds.

Request
{
  "propertyId": "5b1c1f1e-0000-4000-8000-000000000001"
}
Response 200
{
  "ok": true
}

Possible errors: subscription_not_active

Test it

Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.