API referenceorders
Create order
POST
/v1/ordersIdempotency-Key requiredAccepts X-Api-Key · oauthClientCredentials · bearer
The one booking write
Replaces /v1/book, /v1/bookings (write) and /v1/taxi/book.Show more
Replaces /v1/book, /v1/bookings (write) and /v1/taxi/book. Book never re-quotes — price movement at commit is 409 PRICE_CHANGED, never a silent swap. Ambiguous supplier outcome is 202 AMBIGUOUS_RESULT with the order in PENDING_RECONCILIATION. While the tenant is SUSPENDED a new order is refused 403 TENANT_SUSPENDED, with one exception: a same-key, same-body retry of an order request this tenant completed before the suspension is served its stored answer (Idempotency-Replayed true) — nothing new is booked. A fresh, expired or still in-flight key is 403 TENANT_SUSPENDED, a different body under the key 409 IDEMPOTENCY_CONFLICT. Payment check: when payments are served and message.intent.payment.paymentRef names an intent, the platform checks it covers THIS order before the write-ahead row and before any supplier byte. Anything but a funded intent for this tenant, this repriceRef and this total is 409 CONFLICT with details.field message.intent.payment.paymentRef and details.reason one of NOT_FOUND (unknown ref, or another tenant's — the same bytes for both), OTHER_QUOTE (the intent was created from a different repriceRef), AMOUNT_MISMATCH (details.detail AMOUNT or CURRENCY), WRONG_STATE (details.detail is the intent's state: CREATED, REQUIRES_ACTION, CANCELED, FAILED, or PENDING_RECONCILIATION while a payment operation is unresolved), REFUNDED, AUTH_EXPIRED (an uncaptured authorization past its validity), ALREADY_USED (another order already booked on this payment; that order is never named). Nothing was sent to a supplier and the Idempotency-Key is released, so the client fixes the payment and retries. retryable is true only for WRONG_STATE with detail PENDING_RECONCILIATION, and false for every other reason. A second order on a repriceRef that is already spent is 409 CONFLICT with details.field message.intent.repriceRef and details.reason REPRICE_REF_SPENT; when a payment is attached the payment check answers first. A same-key retry of an order that already booked is answered from its stored result without re-checking. Two-step round trip: an order on an OUTBOUND_FIRST FLT offer whose journey is not complete (extension.air.journey.complete false) is 409 CONFLICT with details.reason JOURNEY_INCOMPLETE and details.nextSliceIndex, not retryable; nothing is sent to a supplier and the Idempotency-Key is released. Choose the remaining slices through POST /v1/flights/returns and reprice first. Card-secured slots: message.intent.payment.paymentMethod carries a payment-method token the client obtained from Spreedly; the platform hands the supplier the token and never a card number or security code, and none can be sent: PaymentMethodToken has no such field and a card-number-shaped value anywhere is refused (INSTRUMENT_DATA_REFUSED). Single use, retried with the same Idempotency-Key. Human sessions and system keys are exempt; an ai key and every service token are the AI channel. Wallet: with message.intent.payment.mode WALLET the total is held on the tenant's wallet inside the write-ahead flow before any supplier byte, settled at ticketing or confirmation and released when the supplier fails; an ambiguous outcome keeps the hold until reconciliation, never debiting twice. Too little available is 402 PAYMENT_FAILED with details.reason WALLET_INSUFFICIENT and details.available (Money), and no supplier is called (sandbox scenario Test wallet_insufficient). A tier cap is 403 PERMISSION_DENIED details.reason TIER_CAP_REACHED with details.cap and details.resetAt. TIER_CAP_REACHED is un-reserved. An order of a LIVE_CAPPED tenant that is not a sandbox twin (on any rung) whose total would take today's spend past the daily cap is 403 PERMISSION_DENIED details.reason TIER_CAP_REACHED with details.cap, details.usedToday (Money) and details.resetAt, checked before any payment is taken, any wallet hold is placed or any supplier byte is sent; nothing is written. The cap currency is INR when the activation country is IN, else USD; usedToday counts the tenant's non-cancelled orders since 00:00 UTC, converted to the cap currency at each order's FX snapshot; resetAt is the next 00:00 UTC. The check is per order against today's confirmed and in-flight spend and is SOFT under concurrency: concurrent orders, each under the cap, may together exceed it by at most the orders in flight. An order whose currency the FX snapshot cannot convert to the cap currency is 500 INTERNAL details.reason FX_SNAPSHOT_UNAVAILABLE (the money verbs' existing sub-reason; retryable) and nothing is charged, held or sent. A sandbox twin's orders and tenants of other tiers are never capped. With payment.mode SAVED_METHOD while aikonic.payment-methods.enabled is off the order is 501 NOT_IMPLEMENTED details.reason PAYMENT_METHODS_UNAVAILABLE. payment.mode SAVED_METHOD with payment.methodId charges a saved payment method (POST /v1/payments/methods); a decline is 402 PAYMENT_FAILED details.reason CARD_DECLINED.Headers
- TeststringOptional
Sandbox scenario simulation: price_changed | sold_out | ambiguous | hold_expired | payment_declined | supplier_timeout | partial_search | duplicate_order (case-insensitive).Show more
Sandbox scenario simulation: price_changed | sold_out | ambiguous | hold_expired | payment_declined | supplier_timeout | partial_search | duplicate_order (case-insensitive). Read on every travel verb before the permission wall and idempotency; a scenario sent on a verb it does not apply to has no effect. Every simulated error carries details.simulated true and details.scenario. price_changed (reprice, hold, orders) → 409 PRICE_CHANGED; sold_out → 422 SOLD_OUT; hold_expired (orders) → 409 HOLD_EXPIRED; duplicate_order (orders) → 409 DUPLICATE_ORDER existingOrderRef MO-SIM-DUPLICATE; payment_declined (orders, POST /v1/payments/{paymentId}/confirm) → 402 PAYMENT_FAILED; supplier_timeout → 502 UPSTREAM_UNAVAILABLE; partial_search (search) → two SUPPLIER_DROPPED warnings; ambiguous (orders) → 202 PENDING_RECONCILIATION on an MO-SIM- ref. wallet_insufficient → 402 PAYMENT_FAILED details.reason WALLET_INSUFFICIENT. - Idempotency-KeystringRequired
Mandatory on mutations: **48h TTL**; replay with same body-hash returns the original response with Idempotency-Replayed true; same key + different body is 409 IDEMPOTENCY_CONFLICT; in-flight duplicate…Show more
Mandatory on mutations: **48h TTL**; replay with same body-hash returns the original response with Idempotency-Replayed true; same key + different body is 409 IDEMPOTENCY_CONFLICT; in-flight duplicate is 409 IDEMPOTENCY_IN_PROGRESS. - X-Approval-TokenstringOptional
Redeemed by the payment verbs and by POST /v1/orders (orders.create), cancel (orders.cancel) and amend COMMIT (amend.commit).Show more
Redeemed by the payment verbs and by POST /v1/orders (orders.create), cancel (orders.cancel) and amend COMMIT (amend.commit). Human sessions and system keys are exempt. Single use, ~2 min TTL, bound to tenant + action + resource + amount; any drift fails closed and burns the token.
Request body
- contextMondeeContextRequiredRequest context envelope. domain selects the product; URL carries the verb.
13 child attributes
- domainstringRequired
Canonical code or alias per the domain registry; unknown = 400 UNKNOWN_DOMAIN.Show more
Canonical code or alias per the domain registry; unknown = 400 UNKNOWN_DOMAIN. APTSVC (airport services: meet and assist, porter, buggy, wheelchair, concierge bundles) is registered by this release beside FASTTRK. FNB (dining: restaurant reservations; aliases REST, DINING, RESTAURANT, RESTAURANTS; category DO, money model FREE, artifact CONF_NUMBER, served under the dining service key with base path /v1/dining) is registered since v1.7.0. GIFT (gift cards; category SUPPORT, money model MERCHANT, artifact VOUCHER, served under the gift-cards service key with base path /v1/gift-cards) is described from v1.31.0: until the backend seam change merges, domain GIFT answers 400 UNKNOWN_DOMAIN. AICONT (the Example Content experience-scraping service's operations; category DO, money model MERCHANT, artifact NONE, served under the aicont service key with base path /v1/aicont; a content supplier) has its typed intent from v1.39.0; it answers only where its supplier set is landed and ACTIVE. PARK (airport and cruise-port parking; aliases PRK and PARKING; category SUPPORT, money model MERCHANT, artifact CONF_NUMBER — the supplier's gate barcode is the order's BARCODE document — served under the parking service key with base path /v1/parking) has its typed intent and its verb book from v1.55.0. - actionstringOptionalMirrors the verb; optional (server sets from route)
- enricharray of stringOptional
Opt-in enrichment on shopping answers: EMISSIONS | RATINGS | AMENITIES | ROUTE.Show more
Opt-in enrichment on shopping answers: EMISSIONS | RATINGS | AMENITIES | ROUTE. Absent = the tenant's configured default. Decoration reads cache or the pre-warmed store only and never delays the verb. - session_idstringOptionalYour own id for the user session the call belongs to.
- transaction_idstringOptionalConstant across one shop-to-book journey
- currencystringOptionalISO-4217; absent = tenant default; blank/invalid = 400
- localestringOptionalThe language and region for text in the answer, as a BCP 47 tag (for example en-US).
- posstringOptionalPoint-of-sale market, orthogonal to tenant
- clientReferencestringOptionalCaller's own id; searchable; the reconciliation primitive
- fareSourcePolicystringOptionalBYOC tenants only; narrows, never widens, the configured strategy
- DEFAULT
- OWN_ONLY
- MONDEE_ONLY
- BLEND
- includeUpstreambooleanOptionalDefault false
Ask for the supplier's own answer, verbatim, beside what the platform read from it: Offer.upstream on every offer of a search, poll, detail or flight-returns answer, AirReturnOption.upstream on each…Show more
Ask for the supplier's own answer, verbatim, beside what the platform read from it: Offer.upstream on every offer of a search, poll, detail or flight-returns answer, AirReturnOption.upstream on each listed return, RepriceResponse.message.upstream and OrderItem.upstream. Served only where the deployment enables upstream pass-through; elsewhere a true value is 400 VALIDATION details.reason UPSTREAM_PASS_THROUGH_DISABLED, details.field context.includeUpstream, before any supplier call. Absent or false, nothing changes. The block is informational: offerRef, repriceRef and price stay the only handles and the only price of record. - selectionSelectionPreferencesOptional
context.selection: the caller's offer-selection preferences for this search.Show more
context.selection: the caller's offer-selection preferences for this search. Each field set here replaces the tenant's and the platform's for this search, within the caller's entitlements and the platform's ceilings, unless the tenant has locked request overrides. It never widens reach: a preferred supplier the caller may not reach is ignored with context.warnings[] SELECTION_PREFERENCE_IGNORED. Ignored where selection is off.4 child attributes
- viewstringOptionalSELECTED (one entry per item, alternatives under the winner) or ALL (the flat list, tagged)
- SELECTED
- ALL
- objectivestringOptional
How the winner of an item is picked. CHEAPEST is the lowest comparison total; REFUNDABLE_FIRST the lowest total among offers free to cancel now (else CHEAPEST); PREFERRED_SUPPLIERS the first of…Show more
How the winner of an item is picked. CHEAPEST is the lowest comparison total; REFUNDABLE_FIRST the lowest total among offers free to cancel now (else CHEAPEST); PREFERRED_SUPPLIERS the first of preferSuppliers with an offer inside the tenant's preference band (else CHEAPEST); PLATFORM_DEFAULT defers to the tenant and platform policies. Any other value is 400 VALIDATION details.field context.selection.objective.- CHEAPEST
- REFUNDABLE_FIRST
- PREFERRED_SUPPLIERS
- PLATFORM_DEFAULT
- preferSuppliersarray of stringOptionalSupplier codes as in fareSource.supplier, most preferred first (PREFERRED_SUPPLIERS)
- excludeSuppliersarray of stringOptionalSupplier codes whose offers this search does not show; narrows only
- onBehalfOfOnBehalfOfOptional
Who a desk or agent books FOR: stamped into the audit actor and the clientReference lineage of the order.Show more
Who a desk or agent books FOR: stamped into the audit actor and the clientReference lineage of the order. Send customerId (a customer or traveller id the tenant knows) or traveler (a free-text identity), or both. Attribution only: it grants nothing, and the credential's own actor is still what authorises the call. Audit mapping: the audit actor.onBehalfOf (a string) is customerId when present, otherwise "traveler:<redacted-hash>" (a stable hash of traveler, never the text).2 child attributes
- customerIdstringOptionalA customer or traveller id your own system knows.
- travelerstringOptional
Free-text traveller identity when there is no customer id.Show more
Free-text traveller identity when there is no customer id. Personal data: it is logged redacted, never in clear. A card number in it is 400 VALIDATION details.reason INSTRUMENT_DATA_REFUSED.
- messageobjectRequired
1 child attribute
- intentobjectRequired
The booking intent. Required as built: travelers[] and one of repriceRef or holdRef (backend IntentSchemaRegistry).Show more
The booking intent. Required as built: travelers[] and one of repriceRef or holdRef (backend IntentSchemaRegistry). payment.mode: PSP_TOKEN | CREDIT_LINE | PAY_LATER | SUPPLIER_HOSTED | NONE | PAYMENT_METHOD_TOKEN | OPENTABLE_SMS_LINK | WALLET | SAVED_METHOD. WALLET pays from the tenant's prepaid wallet in the order's currency: no paymentRef; the platform holds the total at book (WALLET_HOLD), settles it at ticketing or confirmation and releases it when the booking fails. Too little available is 402 PAYMENT_FAILED details.reason WALLET_INSUFFICIENT with details.available, and nothing is sent to a supplier. A card-secured dining slot (DiningExtension.creditCardRequired) needs payment.paymentMethod, a Spreedly payment-method token: without it the order is 400 VALIDATION details.reason PAYMENT_METHOD_REQUIRED and nothing is sent. A supplier that demands 3-D Secure refuses the order with 400 VALIDATION details.reason SCA_REQUIRED (nothing booked); the client retries with paymentMethod.threeDs. An In-House slot (cardCapture OPENTABLE_SMS_LINK) takes no token: Example Dining texts the diner, so requiredInfoAnswers.smsOptIn must be true. ENCRYPTED_CARD pays a supplier that charges the card itself (a flight supplier: PaymentType CC, ticketed at book) with a card the caller sealed to GET /v1/payments/card-key: payment.encryptedCard {kid, jwe}, and the lead traveller's billingAddress as the card's billing address. It excludes paymentRef, paymentMethod and checkoutSignature (400 VALIDATION details.reason PAYMENT_MODE_CONFLICT). Refused before the approval grant is redeemed and before anything is written or sent: an envelope that does not open (CARD_ENVELOPE_INVALID), an unusable card (CARD_VALIDATION_FAILED, details.field names the field, never the value), a card not on the rung's test-card list (CARD_NOT_A_TEST_CARD), a missing billing address (BILLING_ADDRESS_REQUIRED), an intent naming the supplier account (Customer, UserInfo, customerId, dkNumber, consolidatorId: CUSTOMER_NOT_CALLER_SUPPLIED), and a supplier that takes no card (501 NOT_IMPLEMENTED CARD_PAYMENT_NOT_SUPPORTED). The card is opened in memory for the one booking call and stored, logged or echoed nowhere. A retry must resend the identical bytes: a re-sealed card under the same Idempotency-Key is 409 IDEMPOTENCY_CONFLICT. SAVED_METHOD charges a method the tenant saved at POST /v1/payments/methods: payment.methodId names it (absent, the default method); the platform charges its stored PSP token through the payments seam inside the write-ahead flow, before any supplier byte, and no card data travels in the order. An unknown or another tenant's methodId is 400 VALIDATION details.field message.intent.payment.methodId; a decline is 402 PAYMENT_FAILED details.reason CARD_DECLINED and nothing is sent to a supplier. SAVED_METHOD excludes paymentRef, paymentMethod and encryptedCard: any of them with it is 400 VALIDATION details.reason PAYMENT_MODE_CONFLICT (the ENCRYPTED_CARD rule), refused before anything is written or sent. WALLET and PSP_TOKEN are unchanged.12 child attributes
- repriceRefstringOptional
- holdRefstringOptional
- clientReferencestringOptionalThe tenant's own reference, echoed on the order
- travelersarray of TravelerOptional
19 child attributes
- typestringOptionalADT | CHD | INF (backend PassengerType); absent = ADT
- ageintegerOptionalRequired when type is CHD or INF
- titlestringOptional
- firstNamestringRequired
- middleNamestringOptional
- lastNamestringRequired
- emailstring · emailOptional
- phoneNumberstringOptionalE.164
- dateOfBirthstring · dateOptional
- genderstringOptionalM | F | X | U; open string
- nationalitystringOptional
- residenceCountrystringOptionalCountry of residence (ISO 3166-1); what entry requirements and insurance rating key on
- residenceAddressPostalAddressOptionalOne postal address
- billingAddressPostalAddressOptionalOne postal address
- shippingAddressPostalAddressOptionalOne postal address
- documentsarray of TravelerDocumentOptional
- loyaltyarray of objectOptional
- answersobjectOptionalPER_TRAVELER requiredInfo answers keyed by RequiredInfo.field; a FILE answer is an uploadId
- leadbooleanOptionalThe lead booker (contact for the order); at most one traveller
- requiredInfoAnswersobjectOptional
PER_BOOKING answers keyed by RequiredInfo.field; a FILE answer is an uploadId.Show more
PER_BOOKING answers keyed by RequiredInfo.field; a FILE answer is an uploadId. FNB diner answers live HERE, never on the traveller: phoneCountry (ISO 3166 alpha-2 of the diner's phone), phone (the diner's phone number as the restaurant should call it, national digits with phoneCountry, or E.164; absent = travelers[lead].phoneNumber), specialRequest (at most 75 characters; longer is 400 VALIDATION details.field message.intent.requiredInfoAnswers.specialRequest), restaurantEmailOptIn, opentableEmailOptIn and smsOptIn (booleans, absent = false: an opt-in is never defaulted to true; smsOptIn must be true for an OPENTABLE_SMS_LINK card capture). - consentsarray of ConsentOptionalThe consents this order was placed under; a RequiredInfo row with consentRequired is refused 400 VALIDATION details.reason CONSENT_REQUIRED without the matching entry
7 child attributes
- consentIdstringRequiredHEALTH_DATA_SHARING | CROSS_BORDER_TRANSFER | THIRD_PARTY_HANDLER | INSURER_TERMS | MARKETING | SUPPLIER_TERMS; open string
- versionstringRequired
- acceptedAtstring · date-timeRequired
- scopestringOptionalORDER | TRAVELER; absent = ORDER
- travelerIndexintegerOptionalWhen scope is TRAVELER
- actorstringOptionalWho accepted — TRAVELER, LEAD_BOOKER or AGENT (then onBehalfOf applies); open string
- supplierstringOptionalThe supplier the consent is for, when supplier-specific
- addOnsarray of AddOnSelectionOptionalSelected add-ons from Offer.addOns[]; must match what the RP- priced
4 child attributes
- codestringRequired
- quantityintegerOptional
- choicestringOptionalThe chosen value for a choice-shaped add-on
- meetSignTextstringOptionalMEET_GREET only — the text on the sign
- optionsarray of objectOptionalExperience option choices (ExperienceOption) when not already fixed at reprice
2 child attributes
- optionIdstringRequired
- valuestringRequired
- taxQuoteSignaturestringOptionalThe tax-quote signature from the reprice, echoed so the order binds to it (an event-ticket supplier)
- experienceSelectionDiningExperienceSelectionOptional
Which experience and how many diners take each of its price options.Show more
Which experience and how many diners take each of its price options. An experience with several prices (e.g. a tasting menu and a wine pairing, or adult and child) is priced per diner: the counts must add up to the party size. On search it narrows the offers to that experience; on reprice, hold and order it fixes the price split the offer is firmed, locked and booked with (Example Dining experience total and reservation `experience` block). A selection whose version is not the experience's current one is 409 CONFLICT details.reason EXPERIENCE_VERSION_CHANGED (re-read the detail); counts that do not add up to the party are 400 VALIDATION details.field message.intent.experienceSelection.3 child attributes
- experienceIdinteger · int64Required
- versionintegerOptionalThe experience version the client showed (DiningExperience.version)
- pricesarray of objectRequired
- paymentobjectOptional
6 child attributes
- modestringOptional
- paymentRefstringOptionalThe paymentId of POST /v1/payments/intent, checked before any supplier byte
- checkoutSignatureCheckoutSignatureOptional
The signed triple a hosted checkout hands the browser.Show more
The signed triple a hosted checkout hands the browser. The platform verifies it against ITS stored provider order id, then reads the provider — the triple is a hint, never the truth. Token references only; never instrument data. - paymentMethodPaymentMethodTokenOptional
A card the CLIENT tokenised with the payment-method vault.Show more
A card the CLIENT tokenised with the payment-method vault. TOKEN ONLY: this object has no field for a card number, an expiry or a security code, and the platform never receives, stores or logs one. The client collects the card in the vault's own iframe (Spreedly iFrame or Express), receives a payment-method token and sends it here; the platform passes the token to the supplier (Example Dining's credit_card object) and keeps only provider, brand and last4 on the order. A digit run that looks like a card number in ANY field of the request is 400 VALIDATION details.reason INSTRUMENT_DATA_REFUSED (PanGuard), and the token itself is never echoed or logged. threeDs is sent only on the RETRY of an order the supplier refused with details.reason SCA_REQUIRED: the same token plus the result of the 3-D Secure challenge the client ran with the vault. - encryptedCardEncryptedCardEnvelopeOptional
v1.36.0. A card sealed by the caller to the key of GET /v1/payments/card-key — byte-compatible with the upstream platform's contract A3.Show more
v1.36.0. A card sealed by the caller to the key of GET /v1/payments/card-key — byte-compatible with the upstream platform's contract A3. jwe is a compact JWE (five base64url segments, no padding): protected header exactly {"alg":"RSA-OAEP-256","enc":"A256GCM","kid":"<kid>"}, a random 32-byte CEK wrapped with RSA-OAEP (SHA-256 hash and MGF1), AES-256-GCM content with a 96-bit IV and 128-bit tag, the protected-header segment's ASCII as AAD. The plaintext is UTF-8 JSON, all strings: {"number":"<13-19 digits>","cvv":"<3-4 digits>","expMonth":"MM","expYear":"YYYY","holderName":"<2-60>"}. kid here and in the header must match each other and a live key. - methodIdstringOptionalwith mode SAVED_METHOD, the saved payment method to charge (SavedPaymentMethod.id); absent, the tenant's default method.
- ancillariesarray of objectOptional
Responses
- 201Order created; state per DOMAIN-CONTRACTS C1 FSM (or PENDING_SUPPLIER for on-request)OrderResponse
- 202OrderResponse
AMBIGUOUS_RESULT: book timed out upstream; order persisted PENDING_RECONCILIATION; poll the order or await order.state_changed.Show more
AMBIGUOUS_RESULT: book timed out upstream; order persisted PENDING_RECONCILIATION; poll the order or await order.state_changed. Never re-book on a different key. - 307
HOME_REGION_REDIRECT: this tenant's writer region is not the region that received the request.Show more
HOME_REGION_REDIRECT: this tenant's writer region is not the region that received the request. Nothing was executed at this region. There is no body. Clients MUST NOT auto-follow this redirect: a cross-origin redirect makes most HTTP stacks drop the Authorization header, and some drop Location altogether. The client MUST re-send the same request (method and body unchanged) to Location WITH its credentials and the SAME Idempotency-Key. Follow-up sends are deduplicated on the Idempotency-Key in the home region. - 400ApiErrorResponse
VALIDATION or UNKNOWN_DOMAIN. A message.intent.payment.paymentRef shaped like a card number is VALIDATION with details.reason INSTRUMENT_DATA_REFUSED and the digits are never echoed: card data never…Show more
VALIDATION or UNKNOWN_DOMAIN. A message.intent.payment.paymentRef shaped like a card number is VALIDATION with details.reason INSTRUMENT_DATA_REFUSED and the digits are never echoed: card data never passes through the platform. Dining: details.reason PAYMENT_METHOD_REQUIRED (a card-secured slot without a token) and SCA_REQUIRED (the supplier demands 3-D Secure; nothing was booked; details.subCode, details.intent, details.paymentMethod and details.retryWith say how to retry: run the challenge, then resend with paymentMethod.threeDs and a NEW Idempotency-Key). payment.mode SAVED_METHOD with paymentRef, paymentMethod or encryptedCard is VALIDATION details.reason PAYMENT_MODE_CONFLICT. - 401ApiErrorResponse
UNAUTHENTICATED — missing or expired token.Show more
UNAUTHENTICATED — missing or expired token. Declared on every operation because `security` is declared globally at the document root: every route is authenticated, so every route can answer 401. - 402ApiErrorResponse
PAYMENT_FAILED — PSP decline reason in details.Show more
PAYMENT_FAILED — PSP decline reason in details. On POST /v1/orders with payment.mode WALLET also details.reason WALLET_INSUFFICIENT with details.required, the order total, and details.available, the wallet's available amount; nothing was sent to a supplier. With payment.mode SAVED_METHOD a declined saved method is details.reason CARD_DECLINED with details.declineCode and details.methodId; nothing was sent to a supplier. - 403ApiErrorResponse
- 405ApiErrorResponse
VALIDATION — the public edge serves GET, POST, PUT, PATCH and DELETE only; any other method is refused before the platform sees it (details.reason METHOD_NOT_ALLOWED, details.source edge).Show more
VALIDATION — the public edge serves GET, POST, PUT, PATCH and DELETE only; any other method is refused before the platform sees it (details.reason METHOD_NOT_ALLOWED, details.source edge). Not retryable as sent. - 409ApiErrorResponse
OFFER_EXPIRED | PRICE_CHANGED | QUOTE_EXPIRED | HOLD_EXPIRED | IDEMPOTENCY_CONFLICT | IDEMPOTENCY_IN_PROGRESS | DUPLICATE_ORDER | CONFLICT.Show more
OFFER_EXPIRED | PRICE_CHANGED | QUOTE_EXPIRED | HOLD_EXPIRED | IDEMPOTENCY_CONFLICT | IDEMPOTENCY_IN_PROGRESS | DUPLICATE_ORDER | CONFLICT. QUOTE_EXPIRED carries details.reason NO_SELL_PRICE_STAMP or SELL_PRICE_STAMP_MISMATCH when the repriceRef has no sell price the platform can book. CONFLICT is the payment check, a spent repriceRef or an incomplete FLT journey; its details.reason values, and which one is retryable, are listed in the operation description. - 413ApiErrorResponse
VALIDATION — the request body is larger than the surface's limit.Show more
VALIDATION — the request body is larger than the surface's limit. Not retryable as sent: shrink the body. Declared on every operation that takes a request body. details carries exactly one key, maxBodyBytes (integer): the limit that applies to this surface, in bytes. - 414ApiErrorResponse
VALIDATION — the request URI (path and query string) is longer than 8 KiB; the public edge refuses it before the platform sees it (details.reason URI_TOO_LONG, details.source edge).Show more
VALIDATION — the request URI (path and query string) is longer than 8 KiB; the public edge refuses it before the platform sees it (details.reason URI_TOO_LONG, details.source edge). Not retryable as sent: send long input in the body of a POST. - 415ApiErrorResponse
VALIDATION — a request body that is not JSON (application/json or application/*+json; a form body only on the OAuth token routes).Show more
VALIDATION — a request body that is not JSON (application/json or application/*+json; a form body only on the OAuth token routes). The public edge refuses it before the platform sees it (details.reason UNSUPPORTED_MEDIA_TYPE, details.source edge). Not retryable as sent: send Content-Type application/json. Declared on every operation that takes a JSON request body. - 422SOLD_OUT or TRAVELER_MISMATCHApiErrorResponse
- 423ApiErrorResponse
PERMISSION_DENIED with details.reason KEY_PAUSED: the API key is PAUSED and every call with it is refused until an Owner or Admin resumes it (POST /v1/keys/{keyPrefix}:resume, a person only); or…Show more
PERMISSION_DENIED with details.reason KEY_PAUSED: the API key is PAUSED and every call with it is refused until an Owner or Admin resumes it (POST /v1/keys/{keyPrefix}:resume, a person only); or details.reason LOOP_DETECTED on the call whose loop paused the key (20 identical requests in 60 s, or 50 holds without a booking or release in 10 min; replays of one Idempotency-Key never count). Not retryable; nextAction stop — the agent stops using the key and tells the person; details carry resumeBy (owner), consoleLink and evidence (ApiKeyPauseEvidence). Nothing was charged, held or sent; holds and orders already made are untouched. A key whose ancestor (the key that minted it, or that key's minter) is PAUSED answers the same 423 KEY_PAUSED, and resuming the ancestor resumes it, so a child never outlasts a pause of its parent. The MCP plane answers the identical body as an isError result. Any key-authenticated route may answer it; it is declared on the order and hold writes, search, reprice and the key routes. - 429ApiErrorResponse
RATE_LIMITED with details.reason VELOCITY_LIMIT: a soft breach of the API key's own scope (reqPerSec, holdsPerHour, cancelsPerDay, lookToBook, spendPerDay) — the first two in 24 hours; the third, or a…Show more
RATE_LIMITED with details.reason VELOCITY_LIMIT: a soft breach of the API key's own scope (reqPerSec, holdsPerHour, cancelsPerDay, lookToBook, spendPerDay) — the first two in 24 hours; the third, or a burst above 5× the limit, pauses the key instead (423 KeyPaused). Retryable after retryAfterMs (mirrored by Retry-After); nextAction slow_down; details carry limit, windowSeconds and the dimension in details.field. The tenant quota of RateLimited and the key's velocity are separate limits. Every call of a minted key also counts against each ancestor key's velocity and spend windows, so minting N children never multiplies the blast radius; spendPerDay is reserved atomically before the order is placed and released if it fails. - 500ApiErrorResponse
INTERNAL. Also raised when the payment check passed but the platform could not record that this order uses the payment: details.field names message.intent.payment.paymentRef and carries no reason.Show more
INTERNAL. Also raised when the payment check passed but the platform could not record that this order uses the payment: details.field names message.intent.payment.paymentRef and carries no reason. Nothing was sent to a supplier and the Idempotency-Key is released, so a retry under the same key is safe. - 501ApiErrorResponse
NOT_IMPLEMENTED — honest fallback, as components/responses/NotImplemented.Show more
NOT_IMPLEMENTED — honest fallback, as components/responses/NotImplemented. also payment.mode SAVED_METHOD while saved payment methods are off on the deployment (aikonic.payment-methods.enabled), details.reason PAYMENT_METHODS_UNAVAILABLE; nothing is charged, written or sent to a supplier. - 502Also the order read routes (getOrder, listOrderDocuments, listOrderEvents, searchOrders) when the order store times out: details.store names the store, retryable true.ApiErrorResponse
- 503ApiErrorResponse
Errors you should handle
Branch on code and honour retryable — never on the HTTP status alone.
| 400 | VALIDATION message.intent.repriceRef or message.intent.holdRef is required | not retryable |
| 400 | UNKNOWN_DOMAIN Unknown domain 'HOTELS'. Did you mean HTL? | not retryable |
| 401 | UNAUTHENTICATED The bearer token is expired. Re-authenticate and retry. | not retryable |
| 402 | PAYMENT_FAILED Card declined by the issuer | not retryable |
| 403 | PERMISSION_DENIED Role lacks the required scope: booking:write | not retryable |
| 403 | TAB_DISABLED Tenant acme-travel is not entitled to sell CRU | not retryable |
| 403 | OUT_OF_SCOPE The token's scope ladder does not reach this customer subtree | not retryable |
| 403 | TENANT_MISMATCH orderRef MO-8KD-2FQ-9XT does not belong to tenant acme-travel | not retryable |
| 403 | TENANT_SUSPENDED This tenant is suspended: new searches, quotes, holds, orders and payments are refused until it is reinstated. Existing orders can still be read, cancelled and amended. | not retryable |
| 405 | VALIDATION This method is not served. | not retryable |
| 409 | CONFLICT This payment has already been used by another order. Create a new payment intent for this booking. | not retryable |
| 409 | PRICE_CHANGED The supplier repriced at commit. The order was not created and nothing was captured. | not retryable |
| 409 | QUOTE_EXPIRED The repriceRef has no sell price this platform can book. Reprice again, then book the new RP-. | not retryable |
| 409 | OFFER_EXPIRED repriceRef RP-H-2ab91c expired at 2026-09-14T17:14:00Z | not retryable |
| 409 | HOLD_EXPIRED holdRef HD-M-4419ab expired at 2026-09-14T17:05:41Z; the seats were released | not retryable |
| 409 | IDEMPOTENCY_CONFLICT Idempotency-Key 7f0c33d1-9a1e-4d2c-9f77-1c0f2b3a4d55 was already used with a different body | not retryable |
| 409 | IDEMPOTENCY_IN_PROGRESS A request with this Idempotency-Key is still executing | retryable |
| 409 | DUPLICATE_ORDER An order already exists for clientReference acme-91827 on this itinerary | not retryable |
| 413 | VALIDATION The request body is larger than this API accepts (262144 bytes). | not retryable |
| 414 | VALIDATION The request URI is longer than 8 KiB. | not retryable |
| 415 | VALIDATION Send application/json. | not retryable |
| 422 | SOLD_OUT The selected fare class is no longer available at the supplier | not retryable |
| 422 | TRAVELER_MISMATCH Supplier rejected traveler[0]: passport expiry precedes the return date | not retryable |
| 423 | PERMISSION_DENIED This API key is paused: 212 holds in 9 min. An Owner or Admin must resume it in the console. | not retryable |
| 429 | RATE_LIMITED This API key exceeded its rate: 10 requests a second. Retry after 1.2 s. | retryable |
| 500 | INTERNAL An unexpected error occurred. Quote the traceId to support. | retryable |
| 501 | NOT_IMPLEMENTED seatmap is NOT_APPLICABLE for HTL; GET /v1/capabilities says so | not retryable |
| 502 | UPSTREAM_UNAVAILABLE Every supplier for HTL is circuit-open; no fan-out was attempted | retryable |
| 503 | PROVIDER_DOWN EXAMPLEHOTELS is unavailable; the order was not attempted and nothing was captured | retryable |