Skip to content

Read a booking curve (pace / pickup)

GET
/v1/analytics/booking-pace
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.

property_id
required
string format: uuid

Property whose curve to read.

arrival_date
required
string format: date

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.

segment
string
default: total
Allowed values: total transient group contract

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.

horizons
string

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.

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.

Media typeapplication/json
object
arrival_date
required

The stay (occupancy) date of this curve.

string format: date
property_id
required
string format: uuid
rows
required

Ordered by snapshot_date_local ascending.

Array<object>
object
adr_otb

revenue_otb / rooms_otb; null when zero rooms are on the books.

string | null format: decimal
captured_at
required
string format: date-time
days_before_arrival
required
integer
pickup

Present only when horizons was requested: one entry per horizon, in request order.

Array<object>
object
horizon_days
required
integer
revenue
string | null format: decimal
rooms
integer | null format: int64
revenue_otb
required

Exact decimal rendered as a string.

string format: decimal
revenue_picked_up_1d
string | null format: decimal
rooms_otb
required
integer format: int64
rooms_picked_up_1d

OTB delta vs. the prior day’s snapshot; null on a curve’s first snapshot.

integer | null format: int64
snapshot_date_local
required
string format: date
segment
required
string
Allowed values: total transient group contract
Example
{
"segment": "total"
}
Cache-Control
string

Always no-store — live data.

Token lacks the analytics:read scope.

Media typeapplication/json

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
error
required
object
code
required

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).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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.

Media typeapplication/json

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
error
required
object
code
required

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).

string
instance_id

Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.

string
message
required

Human-readable explanation of the failure.

string
parameters

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"
}
}