Escapra Developer Docs
A governance-first, PMS-agnostic distribution API. One canonical booking lifecycle. Scoped authorization. Live revalidation. Signed webhooks. Explicit error taxonomy. Queryable lineage.
API contract subject to integration review
Status of this document: conceptual reference for integration evaluation and design. Endpoint paths and payload shapes are subject to integration review and confirmed under a sandbox engagement.
Overview
Escapra is a governance-first distribution API. It connects hotel inventory to authorized B2B demand through a governed layer between hotel supply and approved partners.
Escapra is
A governance, authorization, revalidation, settlement, and audit layer between hotel supply and authorized B2B demand.
Escapra is not
A property management system. An online travel agency. A channel manager. A bed bank.
The API exposes a single canonical booking lifecycle, scoped authorization tokens, an explicit error taxonomy, contracted idempotency on write endpoints, a signed webhook catalog, and queryable lineage per booking. Developers build against one contract — there are no per-partner special cases.
Escapra Concept Model
The platform is described in nouns. Each noun is defined once and referenced everywhere. Implementation details that are not part of the contract are intentionally omitted.
Hotel
The legal and commercial entity that owns the property and authorizes distribution.
Property
The canonical identity of a physical hotel property. One property has many room types and rate plans.
Room Type
A sellable room category under a property (e.g. Deluxe King). Inventory and rates are organized per room type.
Rate Plan
A sellable rate definition under a property (currency, restrictions, cancellation policy). Rate plans carry governance metadata.
Availability Slot
A time-bounded count of sellable units under a room type, with a sourceUpdatedAt freshness marker.
Authorized Partner
A B2B demand partner that a hotel has explicitly authorized to sell, scoped by rate plan, segment, geography, and date range.
Booking
A confirmed (or held) intent against a rate plan and dates. Carries lineage to governance, commission, distribution chain, and settlement.
Governance Decision
The captured decision that authorized (or denied) a booking. Append-only; one per booking lifecycle event.
Settlement Lineage
The chain from booking → governance → property → commission rule → distribution chain → settlement record.
Webhook Event
A signed, replay-safe notification of a lifecycle or scope change on your authorized surface.
Core Platform Objects (Relationships)
How the objects relate:
Hotel
└── Property
├── Room Type
│ └── Availability Slot (sourceUpdatedAt + freshness state)
└── Rate Plan
└── Authorized Partner (scope: rate plans · segment · geography · date range)
└── Booking
├── Governance Decision (append-only)
├── Inventory Decision (FRESH | STALE_WARNING | STALE_BLOCKED)
└── Settlement Lineage (commission rule · distribution chain · settlement record)The relationships above describe the contract, not a database schema. Implementation is per-service isolated; cross-service relationships are resolved by ids, never by shared writeable surfaces.
Booking Lifecycle
The single canonical flow Escapra implements for every booking, regardless of partner or upstream system. This is the centerpiece of the API. Build against this; everything else is reference.
Hotel ↓ (system of record) PMS ↓ (read what is authoritatively exposed) Escapra Governance Layer ↓ (scoped authorization check) Authorized Partner ↓ (quote → hold → confirm) Booking Request ↓ (inventory + rate revalidation against source of truth) Confirmation — or — 409 PRICE_CHANGED → re-accept ↓ Settlement (atomic, idempotent, lineage end-to-end) ↓ Audit (append-only)
Step-by-step
- 01
Partner · Quote
Request availability under your authorized rate plans for given dates and occupancy.
- 02
Escapra · Resolve scope
Verify your authorization scope, classify inventory freshness, and return only what you may sell.
- 03
Partner · Hold
Create a hold with an Idempotency-Key. A governance decision is captured against the booking-in-progress.
- 04
Escapra · Capture
Record the governance decision and the inventory decision (FRESH / STALE_WARNING / STALE_BLOCKED) for this attempt.
- 05
Partner · Confirm
Submit confirmation with guest detail and the original Idempotency-Key.
- 06
Escapra · Revalidate
Live revalidation against the hotel's source of truth. If the rate matches, write the booking with lineage; if not, return 409 PRICE_CHANGED.
- 07
Partner · Re-accept
On 409 PRICE_CHANGED, you receive the new rate and must explicitly re-accept (or decline).
- 08
Escapra · Settle
Once confirmed, the booking flows into settlement under its commission rule and distribution chain.
- 09
Escapra · Audit
Every decision is captured to an append-only audit. History is never updated; lineage is queryable per booking.
API contract subject to integration review
Endpoint paths for quote / hold / confirm are subject to integration review. The lifecycle shape above is stable; wire-level shapes are aligned per integration in sandbox before production activation.
Inventory & Availability
Availability slots carry a sourceUpdatedAt marker and a freshness classification. The classification is observable on every quote and recorded on every booking attempt.
Availability is current and bookable. Quote and hold flow normally.
Availability is older than the soft threshold. Bookable, but a freshness signal is attached to the booking record.
Availability exceeds the hard freshness threshold. Quotes and bookings are blocked, not silently confirmed.
Out-of-order ingest protection
Ingest is guarded against out-of-order updates: a later sourceUpdatedAt never silently overwrites a freshness classification with an older one. The platform records skipped-stale events for observability.
Live validation where available
When a hotel’s source of truth exposes a live capability surface, Escapra revalidates against it at the moment of booking confirmation. When the capability surface is degraded, the platform fails closed rather than book unsafely.
Revalidation Contract
Every booking is revalidated against the hotel’s source of truth before confirmation. This is the contract. There is no path that confirms a booking without revalidation.
- 01
You submit confirm with the original Idempotency-Key and the rate you quoted.
- 02
Escapra revalidates against the hotel's source of truth at the moment of confirmation.
- 03
If the rate is unchanged, the booking is written with full lineage and you receive a confirmation.
- 04
If the rate has changed, Escapra returns 409 PRICE_CHANGED with the new rate, the prior quote, and the reason.
- 05
You explicitly re-accept (which confirms at the new rate) or decline (which releases the hold).
- 06
If inventory is stale or capability has degraded, Escapra fails closed — the booking does not confirm.
# Conceptual: confirmation response on rate drift
HTTP/1.1 409 Conflict
Content-Type: application/json
{
"error": "PRICE_CHANGED",
"quoted": { "currency": "EUR", "total": 1240.00 },
"revalidated": { "currency": "EUR", "total": 1280.00 },
"reason": "rate_plan_updated_between_quote_and_confirm",
"next": "re_accept_with_new_total_or_decline"
}API contract subject to integration review
Exact payload field names are subject to integration review; the contract shape above is stable.
Webhooks & Events
Subscribe to lifecycle and scope-change events on your authorized surface. Delivery is at-least-once, payloads are HMAC-signed, and event ids let you dedupe and replay safely.
| Event | Fires when |
|---|---|
| booking.created | A booking has been created in hold state, awaiting confirmation. |
| booking.confirmed | A booking has been confirmed and lineage written. |
| booking.cancelled | A booking has been cancelled under governed terms. |
| availability.changed | Availability on a rate plan within your scope has changed. |
| rate.changed | A rate plan within your scope has been updated by the hotel. |
| authorization.updated | Your authorization scope has been changed (granted, restricted, or revoked). |
| settlement.generated | A statement of account or settlement record has been generated for your scope. |
| incident.created | An operational incident affecting your scope has been raised. |
Delivery contract
- — At-least-once delivery. Dedupe by
event_id. - — Signed payload. Verify the HMAC signature against your subscription secret on every event.
- — Retry with backoff. Non-2xx responses are retried with exponential backoff; dead-letter behavior is documented on the subscription.
- — Replay safety. Same
event_iddelivered twice describes the same fact — never two distinct facts.
API contract subject to integration review
Exact webhook payload shapes and subscription endpoints are subject to integration review and confirmed in sandbox.
Error Model
Errors are a stable taxonomy at the category level. Messages may evolve; categories do not. The categories below describe behavior — not internal causes — so client code paths stay stable.
| Code | HTTP | Meaning | Retry |
|---|---|---|---|
| AUTHORIZATION_REQUIRED | 401 | No valid token, or token is missing scope claims. | no |
| AUTHORIZATION_DENIED | 403 | Token is valid but the requested action exceeds the authorization scope hotels granted you. | no |
| PRICE_CHANGED | 409 | The rate revalidated to a different value at confirmation. Re-accept explicitly or decline. | after re-accept |
| AVAILABILITY_CHANGED | 409 | Inventory available at quote is no longer available at confirmation. Re-quote and retry. | after re-quote |
| STALE_INVENTORY_BLOCKED | 409 | Availability has exceeded the freshness threshold. Wait for ingest, then re-quote. | after re-quote |
| PMS_UNAVAILABLE | 503 | The hotel's upstream system of record is unavailable or degraded. Escapra fails closed by design. | safe |
| BOOKING_REVALIDATION_FAILED | 409 | Revalidation against the source of truth failed for a reason not covered above (e.g. capability degradation). | conditional |
| IDEMPOTENCY_CONFLICT | 409 | Same Idempotency-Key + different payload. Generate a fresh key for the new payload. | no |
| RATE_LIMITED | 429 | Too many requests on this route class. Honor the Retry-After header. | safe |
| INTERNAL_ERROR | 5xx | Escapra-side error. Retries with the same Idempotency-Key are safe. | safe |
Idempotency & retries
- — Every write endpoint accepts an
Idempotency-Keyheader. - — Same key + same payload → same result. Same key + different payload →
IDEMPOTENCY_CONFLICT. - — Retries on
INTERNAL_ERROR/PMS_UNAVAILABLEwith the same key are safe. - — Backoff with jitter. Honor
Retry-AfteronRATE_LIMITED.
Getting Started
The integration path is sandbox-first. Production activation is a joint readiness review with Escapra and an authorizing hotel — never a public self-serve switch.
- 01
Request sandbox access
Tell us your segment and integration profile. Sandbox keys are issued against a synthetic property, partner, and scope set.
- 02
Confirm authentication model
Bind your client to an authentication model (OAuth 2.0 for partner platforms, API key for server-to-server). Tokens are scoped to your authorization.
- 03
Map properties
Validate that your local property model maps to Escapra Property identities. Mapping is unidirectional — Escapra reads what the hotel authoritatively exposes.
- 04
Sync rooms / rates / availability
Read room types, rate plans, and availability slots within your authorized scope. Respect freshness state on every slot.
- 05
Test booking lifecycle
Exercise the full lifecycle in sandbox: quote → hold → revalidate → confirm. Force PRICE_CHANGED, AVAILABILITY_CHANGED, and STALE_INVENTORY_BLOCKED paths.
- 06
Configure webhooks
Subscribe to the events your integration depends on. Verify HMAC signatures, dedupe by event id, and tolerate at-least-once delivery.
- 07
Run pilot validation
Pilot scoping is a joint conversation with Escapra and an authorizing hotel. The pilot exercises every lifecycle in a controlled scope.
- 08
Production readiness review
Joint review covers scope, idempotency hygiene, webhook delivery, error handling, and incident response — before production activation.