Read a booking curve (pace / pickup)
const url = 'https://api.aerandil.com/v1/analytics/booking-pace?property_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0&arrival_date=2026-04-15&segment=total';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.aerandil.com/v1/analytics/booking-pace?property_id=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0&arrival_date=2026-04-15&segment=total' \ --header 'Authorization: Bearer <token>'The booking curve for one (property, stay date, segment): every daily on-the-books snapshot the booking-pace sweep has recorded, ordered by snapshot date (analytics decision doc 04 §5a / §5f).
A typed fact query, not a metric. A curve is ordered rows with self-join deltas, which the conformed-metric grammar cannot express; this is the first member of the /v1/analytics/* fact-query family.
OTB semantics. Each row freezes the on-the-books state at the property-local cutoff (default 23:59): reservation-nights of reservations in confirmed / modified / in_house; held, cancelled, no_show, and checked_out are excluded. Rows exist for every stay date in the lookahead horizon — zero-OTB dates included — and are immutable once written: a later cancellation shows up as negative pickup in later rows, never as a mutation.
Pickup horizons. rooms_picked_up_1d / revenue_picked_up_1d are stored; longer horizons (horizons=7,14,30) are computed read-time by diffing against the row that many snapshot days earlier in the same curve.
Live data: always Cache-Control: no-store.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Property whose curve to read.
The stay (occupancy) date whose booking curve to read, YYYY-MM-DD. Named for the industry’s pace vocabulary; a multi-night stay contributes a night to each stay date it covers.
total (default) | transient | group | contract. The sweep writes total for every property plus one curve per segment the property actually sells, discovered from the horizon rather than from the declared vocabulary — so a segment a house never sells returns an empty curve, and total is by construction the sum of the segments plus whatever is unsegmented.
Comma-separated pickup horizons in days (e.g. 7,14,30; at most 5, each 1–365). Adds a pickup array per row, diffed against the row that many snapshot days earlier; a horizon with no prior row yields nulls.
Responses
Section titled “Responses”The booking curve, ordered by snapshot_date_local ascending. An unknown property or a curve with no snapshots yet is an empty rows array, not a 404.
object
The stay (occupancy) date of this curve.
Ordered by snapshot_date_local ascending.
object
revenue_otb / rooms_otb; null when zero rooms are on the books.
Present only when horizons was requested: one entry per horizon, in request order.
object
Exact decimal rendered as a string.
OTB delta vs. the prior day’s snapshot; null on a curve’s first snapshot.
Example
{ "segment": "total"}Headers
Section titled “Headers”Always no-store — live data.
Token lacks the analytics:read scope.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}Malformed arrival_date, unknown segment, or out-of-range horizons.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}