Skip to main content
Preview: nothing is served yet. This describes the Distribution API contract (version 1.0.0). Try it against a mock of the contract (Testing).
Your channel keeps its own copy of what hosts publish to it, and brings it up to date by asking what changed. Webhooks tell you sooner, but the lists and the event log are the source: anything you missed is still there for 35 days.

Lists

GET /locations, /owners, /properties, /amenities and /webhooks answer a page:
  • limit is 1 to 500, 100 by default; above 500 is refused.
  • To read the next page, send next_cursor back as cursor. It is opaque and bound to the query that produced it. It is null on the last page.
  • /locations, /owners and /properties filter by status, for example status=active,inactive, and /properties also by location_id and owner_id.
  • A single resource is GET /locations/{location_id}, /owners/{owner_id}, /properties/{property_id}.
  • A read carries an ETag (every one except GET /availability); send it back as If-None-Match and an unchanged answer is 304 Not Modified, everywhere but the webhook delivery logs (/webhooks/{webhook_id}/deliveries).
Properties name their location_id and owner_id, so read locations and owners before the properties that point to them.

The first copy, then only the changes

1

Read everything once

List each resource without updated_since, following next_cursor to the end. Keep every resource with its version, and remember the largest updated_at you received.
2

Ask for what changed since then

List again with updated_since set to that largest updated_at. The bound is inclusive, so you need no overlap: what changed at that very second comes back again, and its version tells you whether you already have it.
3

Apply by version

Apply a resource only when its version is higher than the one you hold, and ignore a lower one. A version grows with every change visible to your channel, but it is not a counter: do not expect consecutive values.
4

Start over when the window has passed

An updated_since older than the retention window, 35 days, is answered 410 with sync-window-expired. Resync from scratch: read everything once, as in the first step.

One lifecycle for every resource

Locations, owners, properties, amenities and webhook endpoints share one status, with the same meaning everywhere: A withdrawn or deleted resource is a tombstone, on every resource, and nothing else is sent:
Tombstones appear in a list only when you send updated_since; without it, only active and inactive resources exist. A single resource read by its id answers with its tombstone. Handle all four values on every resource, including one that resource does not reach today.

Availability and prices

Availability is read per property and per night, in the property’s own dates.
  • GET /properties/{property_id}/availability?from=2026-12-20&to=2026-12-27 answers a property’s nights in a window: to is exclusive, the window is at most 365 nights and within the published horizon. A from before the property’s today is served from today, and the response says which window it served. A window beyond the horizon is answered 400 with window-beyond-horizon and the property’s horizon_end. A withdrawn or deleted property answers 404.
  • GET /availability?updated_since=…&from=…&to=… answers the nights that changed, grouped by active or inactive property. A page ends at limit properties or 5,000 nights, whichever comes first, so a property’s nights may continue on the next page under the same property_id: apply them by date. A page costs max(1, ceil(nights / 1000)) units of your rate limit.
Each night carries units_available (0 is sold out), min_stay and max_stay for an arrival that night, closed_to_arrival, closed_to_departure, and a rate per rate plan. A rate’s price is for base_occupancy guests, as the guest pays it (VAT included, markup applied), and is null when the rate is closed; extra_guest_price is the price of one more adult, 0 when free, null when the price covers everyone.

The event log

GET /events is your log, in commit order, of what changed, retained for 35 days. Store the last_event_id of each page and send it back as since; next_cursor is null once you are caught up. Without since the log starts at its oldest retained event. Only the event types your key’s scopes cover appear: availability.updated needs read:ari. A since behind the retained log is answered 410 with event-cursor-expired and the latest_event_id: resync with updated_since, then continue the log from latest_event_id. An event names a resource and its version, or, for availability.updated, a property and a range of nights (from, to exclusive) with no version: re-read that range. The event types are location.created, location.updated, location.deleted, owner.created, owner.updated, owner.deleted, property.created, property.updated, property.deleted, property.distributed, property.withdrawn and availability.updated, and more may be added.