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.
/v1/meThe key you are calling with
{
"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.
/v1/amenity-categoriesAmenity categories
Required scope: catalog:read
localequery | Language of names: tr or en. |
{
"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.
/v1/amenitiesAll 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
localequery | Language of names: tr or en. |
{
"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.
/v1/property-typesProperty types
Required scope: catalog:read
localequery | Language of names: tr or en. |
{
"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.
/v1/room-typesRoom types
Required scope: catalog:read
localequery | Language of names: tr or en. |
{
"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.
/v1/bed-typesBed types
Keys used in rooms[].beds[].type; sleeps is how many people one bed takes.
Required scope: catalog:read
localequery | Language of names: tr or en. |
{
"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.
/v1/legal-formsCompany legal forms of a country
What a company can be in that country (LTD, AS in Turkey; LLC, C_CORP in the US). individual marks sole traders.
Required scope: catalog:read
countryquery · req | ISO 3166-1 alpha-2 code. |
{
"data": [
{
"key": "LTD",
"name": "Limited Şirket (Ltd. Şti.)"
}
]
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/geo/countriesCountries
Required scope: catalog:read
localequery | Language of names: tr or en. |
{
"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.
/v1/geo/nodesChildren 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 · req | Id of the parent node. |
localequery | Language of names: tr or en. |
{
"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.
/v1/geo/searchSearch places by name
Required scope: catalog:read
qquery · req | At least two characters. |
localequery | Language of names: tr or en. |
countryquery | Limit to a country node id. |
{
"data": [
{
"id": "…",
"type": "SUBURB",
"name": "Kalkan",
"path": "Kaş, Antalya, Turkey"
}
]
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/currenciesCurrencies
Required scope: catalog:read
{
"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.
/v1/localesLanguages
Required scope: catalog:read
{
"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.
/v1/propertiesQuery 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
qquery | Name, code or address contains. |
geoIdquery | A place id from /v1/geo/*; matches that place and everything below it. |
typesquery | Comma-separated property type keys. |
guestsquery | Sleeps at least this many. |
bedroomsquery | At least this many bedrooms. |
bathroomsquery | At least this many bathrooms. |
amenitiesquery | Comma-separated amenity keys; the property must have all of them. |
subscribedquery | true only properties you subscribe to, false only those you do not. |
limitquery | Page size, at most 60 (default 25). |
cursorquery | The nextCursor of the previous page. |
localequery | Language of names: tr or en. |
{
"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.
/v1/properties/{id}One property
Required scope: properties:read
idpath · req | The property id (UUID). |
localequery | Language of names: tr or en. |
{
"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.
/v1/properties/{id}/mediaPhotos
Each photo comes in thumb, medium and large WebP. Fetch the URLs with the same Bearer key.
Required scope: properties:read
idpath · req | The property id (UUID). |
{
"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.
/v1/media/{imageId}/{size}A photo file
Required scope: properties:read
imageIdpath · req | Photo id. |
sizepath · req | thumb, medium or large. |
(binary WebP)/v1/properties/{id}/exportDownload 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 · req | The property id (UUID). |
formatquery | json (default), zip, calendar.csv or rates.csv. |
localequery | Language of names: tr or en. |
(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.
/v1/properties/{id}/subscriptionSubscribe
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 · req | The property id (UUID). |
{
"message": "We run 40 villas in Kaş."
}{
"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.
/v1/properties/{id}/subscriptionUnsubscribe
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 · req | The property id (UUID). |
Possible errors: subscription_not_foundsubscription_has_bookings
/v1/subscriptionsYour subscriptions
Required scope: properties:read
statusquery | REQUESTED, ACTIVE, REJECTED or ENDED. |
{
"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.
/v1/subscriptions/{id}One subscription
Required scope: properties:read
idpath · req | The subscription id (UUID). |
{
"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.
/v1/properties/{id}/calendarCalendar
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 · req | The property id (UUID). |
fromquery · req | First day, YYYY-MM-DD. |
toquery · req | Last day, exclusive (a stay ends on the day it departs). |
{
"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.
/v1/properties/{id}/calendar.icsCalendar 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 · req | The property id (UUID). |
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.
/v1/properties/{id}/ratesRates
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 · req | The property id (UUID). |
fromquery · req | First day, YYYY-MM-DD. |
toquery · req | Last day, exclusive (a stay ends on the day it departs). |
{
"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.
/v1/properties/{id}/availabilityAvailability 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 · req | The property id (UUID). |
checkInquery · req | Arrival date. |
checkOutquery · req | Departure date. |
guestsquery | Number of guests (default 1). |
extrasquery | Paid amenities to quote, comma separated: key for a property-wide amenity, key@roomId for one in a room. |
{
"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.
/v1/availability/searchSearch 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
{
"checkIn": "2027-07-10",
"checkOut": "2027-07-14",
"guests": 4,
"propertyIds": [
"5b1c1f1e-0000-4000-8000-000000000001"
]
}{
"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.
/v1/holdsPlace 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
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"checkIn": "2027-07-10",
"checkOut": "2027-07-14",
"guests": 4,
"holdHours": 24,
"holdRef": "TALEP-1042"
}{
"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.
/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 · req | The hold id (UUID). |
{
"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.
/v1/holds/{id}/confirmConfirm 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 · req | The hold id (UUID). |
{
"externalRef": "REZ-2027-0042"
}{
"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.
/v1/holds/{id}/extendAsk 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 · req | The hold id (UUID). |
{
"minutes": 15
}{
"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.
/v1/waitlistYour queue entries
Required scope: reservations:read
{
"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.
/v1/waitlistQueue 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
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"checkIn": "2027-07-10",
"checkOut": "2027-07-14",
"guests": 4,
"holdRef": "TALEP-1043"
}{
"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.
/v1/waitlist/{id}Leave the queue
Required scope: reservations:write
idpath · req | The entry id (UUID). |
nullPossible errors: waitlist_entry_not_found
/v1/holds/{id}Release a hold
Required scope: reservations:write
idpath · req | The hold id (UUID). |
{
"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.
/v1/reservationsSend 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
{
"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"
}{
"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.
/v1/reservationsList reservations
Required scope: reservations:read
statusquery | HOLD, CONFIRMED, CANCELLED or EXPIRED. |
propertyIdquery | Only this property. |
limitquery | At most 500. |
{
"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.
/v1/reservations/{id}One reservation
Required scope: reservations:read
idpath · req | The reservation id (UUID). |
{
"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.
/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 · req | The reservation id (UUID). |
{
"checkOut": "2027-07-15",
"guests": 5
}{
"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.
/v1/reservations/{id}/cancelSend 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 · req | The reservation id (UUID). |
{
"reason": "Guest cancelled"
}{
"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.
/v1/eventsEvent 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
afterquery | Return events after this id (evt_123 or 123). |
propertyIdquery | Only this property. |
typequery | Only this event type. |
limitquery | At most 500 (default 100). |
{
"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.
/v1/events/{id}One event
Required scope: events:read
idpath · req | Event id, evt_…. |
{
"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.
/v1/webhook-endpointsList endpoints
Required scope: webhooks:manage
{
"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.
/v1/webhook-endpointsAdd 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
{
"url": "https://example.com/hooks/bp",
"description": "PMS",
"events": [
"calendar.updated",
"reservation.cancelled"
]
}{
"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.
/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 · req | The endpoint id (UUID). |
{
"active": true
}{
"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.
/v1/webhook-endpoints/{id}Delete an endpoint
Required scope: webhooks:manage
idpath · req | The endpoint id (UUID). |
/v1/webhook-endpoints/{id}/testSend 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 · req | The endpoint id (UUID). |
{
"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.
/v1/webhook-endpoints/{id}/rotate-secretRotate 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 · req | The endpoint id (UUID). |
{
"secret": "whsec_…"
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/webhook-deliveriesDelivery log
Required scope: webhooks:manage
endpointIdquery | Only this endpoint. |
statusquery | PENDING, SUCCESS or FAILED. |
limitquery | At most 200. |
beforequery | Only deliveries created before this timestamp (for paging). |
{
"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.
/v1/webhook-deliveries/{id}/retrySend a delivery again
Required scope: webhooks:manage
idpath · req | The delivery id (UUID). |
{
"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.
/v1/sandbox/resetsandbox onlyReset the sandbox
Deletes your sandbox reservations and properties and creates the three sample properties again.
{
"status": "reset"
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/sandbox/simulate/owner-blocksandbox onlyThe owner closes dates
Triggers calendar.updated with source: "owner".
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"from": "2027-02-01",
"to": "2027-02-05"
}{
"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.
/v1/sandbox/simulate/owner-unblocksandbox onlyThe owner reopens dates
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"from": "2027-02-01",
"to": "2027-02-05"
}{
"opened": [],
"stillClosed": []
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/sandbox/simulate/other-agency-bookingsandbox onlyAnother agency books
Closes the dates and triggers calendar.updated with source: "agency", exactly what you receive when a competitor books a shared property.
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"from": "2027-02-10",
"to": "2027-02-12"
}{
"ok": true
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/sandbox/simulate/price-changesandbox onlyThe owner changes the price
Triggers rates.updated.
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"from": "2027-02-20",
"to": "2027-02-25",
"nightlyMinor": 29900
}{
"ok": true
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/sandbox/simulate/property-updatesandbox onlyThe owner edits the listing
Triggers property.updated. name really renames the sandbox property.
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001",
"name": "Villa Mavi Deluxe"
}{
"ok": true
}Test it
Only sandbox keys starting with bp_test_ are accepted. The key is kept in this tab's browser session only.
/v1/sandbox/simulate/subscription-approvesandbox onlyThe owner approves your request
For a property you subscribed to that waits for approval. Triggers subscription.approved.
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001"
}{
"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.
/v1/sandbox/simulate/subscription-revokesandbox onlyThe owner ends your subscription
Triggers subscription.revoked and releases your holds.
{
"propertyId": "5b1c1f1e-0000-4000-8000-000000000001"
}{
"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.