{"openapi":"3.0.0","paths":{"/health":{"get":{"operationId":"healthLiveness","parameters":[],"responses":{"200":{"description":"The process is alive.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerseHealthDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Liveness check (does not touch dependencies)","tags":["Health"],"security":[],"x-billable-search":false,"x-idempotency":"none"}},"/health/ready":{"get":{"operationId":"healthReadiness","parameters":[],"responses":{"200":{"description":"Ready.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerseHealthDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"Not ready — the database is unreachable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TerseHealthDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Readiness check (database only)","tags":["Health"],"security":[],"x-billable-search":false,"x-idempotency":"none"}},"/health/full":{"get":{"operationId":"healthFull","parameters":[],"responses":{"200":{"description":"State per dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FullHealthDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Per-dependency state (no internal detail)","tags":["Health"],"security":[],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/ping":{"get":{"description":"Deliberately without a key: someone starting out has to be able to prove that he reaches us before he sorts out credentials. A 401 here would hide a networking problem behind a permission problem.","operationId":"ping","parameters":[],"responses":{"200":{"description":"The API is reachable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PingDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Reachability check. No API key required.","tags":["Meta"],"security":[],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/account":{"get":{"description":"The first call after `ping`. Answers in one round trip who you are, what you may do and where your limits are — so that none of it has to be guessed from 403s.\n\nRequired scope: `account:read`.","operationId":"getAccount","parameters":[],"responses":{"200":{"description":"Account, permissions and limits of this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"partnerApiKey":[]}],"summary":"Partner, settlement modes, scopes and limits of this key.","tags":["Meta"],"x-required-scopes":["account:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/account/ledger":{"get":{"description":"Settlement mode A only. `availableCents` is what a booking may draw on right now: balance plus credit limit. Money held for a booking in flight is already out of the balance — holds are stored as negative entries — so do not subtract `heldCents` again. It is shown so you can explain the number, not so you can compute with it.","operationId":"getLedgerBalance","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerBalanceDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"partnerApiKey":[]}],"summary":"Your prepaid balance","tags":["Account"],"x-required-scopes":["ledger:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/account/ledger/entries":{"get":{"description":"The audit trail behind the balance. There is no stored balance — it is the sum of these entries, which is why they can be reconciled against your own books line by line.","operationId":"listLedgerEntries","parameters":[{"name":"kind","required":false,"in":"query","description":"Restrict to one movement type, e.g. `HOLD`, `CHARGE`, `RELEASE`, `DEPOSIT`.","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"At most 100.","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","description":"From a previous `nextCursor`.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LedgerEntryPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"partnerApiKey":[]}],"summary":"Every movement on your account, newest first","tags":["Account"],"x-required-scopes":["ledger:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/account/quota":{"get":{"description":"The live counter behind the `X-Search-Quota-*` headers, without having to make a search to see it. Reading it is free and does not count.\n\nThe day is YOUR calendar day: the allowance resets at midnight in your time zone, not at midnight UTC.\n\nRequired scope: `account:read`.","operationId":"getSearchQuota","parameters":[],"responses":{"200":{"description":"Where the daily search allowance stands right now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchQuotaDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"security":[{"partnerApiKey":[]}],"summary":"Searches used today, and what is left of the free allowance","tags":["Account"],"x-required-scopes":["account:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/countries":{"get":{"operationId":"listEsimCountries","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EsimCountryDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Countries with eSIM coverage","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/regions":{"get":{"operationId":"listEsimRegions","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EsimRegionDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Regional eSIM bundles","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/plans":{"get":{"description":"Free — the catalogue comes from our own database and costs us nothing upstream, so it never counts against your search quota.","operationId":"listEsimPlans","parameters":[{"name":"country","required":false,"in":"query","schema":{"example":"DE","type":"string"}},{"name":"region","required":false,"in":"query","schema":{"example":"EU","type":"string"}},{"name":"planType","required":false,"in":"query","schema":{"enum":["data","unlimited","voice_sms"],"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"type":"number"}},{"name":"pageSize","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimPlanPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Plans at your net price","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/plans/{planId}":{"get":{"operationId":"getEsimPlan","parameters":[{"name":"planId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimPlanDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One plan at your net price","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/orders":{"post":{"description":"What this call does depends on the settlement mode of the key you present, and on nothing else. It is not a choice per request: sending `settlement` in the body is a CHECK, and a value that contradicts your key is refused rather than obeyed.\n\n**`partner` settlement (mode A).** You are the merchant. We reserve the net price on your account, order from the supplier, then charge what was actually due — three steps, inside this one call. If the supplier declines, the reservation is released and you are not charged. You get the eSIM back provisioned, `checkout` is `null`, and you have already invoiced your own customer.\n\n**`vacabee` settlement (mode B).** WE are the merchant and your TRAVELLER pays us. Your account is never touched — there is no reservation, no charge and no `402`. The order comes back at `AWAITING_PAYMENT` with a `checkout.url`: send your traveller there. Nothing is bought at the supplier until he has paid, so nothing is held for him either — the link carries a price with a deadline, and letting it run out is an ordinary outcome, not a fault. You are told either way through the `esim.provisioned` / `esim.failed` webhooks.\n\n`402 insufficient_funds` and `403 account_not_active` can only reach a `partner` key: they are answers about an account that mode B does not use.","operationId":"createEsimOrder","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEsimOrderDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"The balance does not cover this operation (`insufficient_funds`), or the account is not active (`account_not_active`). Do NOT retry — the answer only changes once a top-up happens. `error.availableCents` and `error.requiredCents` name the shortfall, `error.currency` the account's currency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Order an eSIM — who pays follows your key","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:order"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"},"get":{"operationId":"listEsimOrders","parameters":[{"name":"limit","required":false,"in":"query","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimOrderPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Your eSIM orders, newest first","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/orders/{id}":{"get":{"operationId":"getEsimOrder","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One order with its activation data","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/esim/orders/{id}/usage":{"get":{"description":"Falls back to the last known values if the supplier is briefly unreachable — `status: null` tells you that is what you are seeing.","operationId":"getEsimUsage","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EsimUsageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Live data usage","tags":["eSIM"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["esim:read"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/webhooks/endpoints":{"get":{"operationId":"listWebhookEndpoints","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpointDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Your webhook endpoints — never the signing secret","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"},"post":{"description":"Store the `signingSecret` before you do anything else with the response. It is the only thing that tells a delivery of ours apart from any other POST to your public endpoint, and we cannot show it to you a second time.","operationId":"createWebhookEndpoint","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpointDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedWebhookEndpointDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Add an endpoint — the signing secret comes back once and never again","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"required"}},"/v1/webhooks/endpoints/{id}":{"patch":{"operationId":"updateWebhookEndpoint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchWebhookEndpointDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Change url, events, description or status","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"none"},"delete":{"description":"The history goes with it. To stop deliveries but keep the record — a planned maintenance, say — PATCH the endpoint to `DISABLED` instead.","operationId":"deleteWebhookEndpoint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":"Removed. Deliveries already recorded stay in the history — deleting the endpoint does not erase what we tried to send you.","headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Remove an endpoint and its delivery history","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"none"}},"/v1/webhooks/endpoints/{id}/rotate-secret":{"post":{"description":"For 24 hours afterwards every delivery carries TWO `v1` signatures — the new secret and the old one — so you can deploy the new value without the deliveries in between failing your check. Accept the delivery if any `v1` matches; the SDK already does.","operationId":"rotateWebhookSecret","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateWebhookSecretDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedWebhookEndpointDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Issue a new signing secret without losing an event","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"required"}},"/v1/webhooks/endpoints/{id}/test":{"post":{"description":"Runs through the exact same path as a real event — TLS, signature, your handler — and shows up in the delivery history with the response you gave. A test that takes a shortcut only proves the shortcut. Do this before anything real depends on the endpoint.","operationId":"testWebhookEndpoint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestResultDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Send a sample delivery to prove the path","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"required"}},"/v1/webhooks/deliveries":{"get":{"description":"Filter by `status=EXHAUSTED` to find exactly the events that need your attention: those are the ones where the automatic attempts ran out and nothing more happens on its own.","operationId":"listWebhookDeliveries","parameters":[{"name":"endpointId","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"enum":["PENDING","SUCCEEDED","FAILED","EXHAUSTED"],"type":"string"}},{"name":"eventType","required":false,"in":"query","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"1–100, default 25","schema":{"type":"number"}},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryListDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Every delivery, newest first — status, code and last error","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/webhooks/deliveries/{id}":{"get":{"description":"This is where \"it returned 500\" becomes \"it returned 500 saying `missing customer_id`\" — the second is debuggable, the first is not.","operationId":"getWebhookDelivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryDetailDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One delivery with every attempt: request, response, status code","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/webhooks/deliveries/{id}/retry":{"post":{"description":"Repeats the identical body with a fresh signature. The timestamp has to be new, otherwise your own replay window would reject it. Answers synchronously with what your endpoint said this time.","operationId":"retryWebhookDelivery","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookRetryResultDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Send it again now — allowed after the automatic attempts ran out","tags":["Webhooks"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["webhooks:manage"],"x-rate-limit-class":"DEFAULT","x-billable-search":false,"x-idempotency":"required"}},"/v1/hotels/destinations":{"get":{"operationId":"lookupHotelDestinations","parameters":[{"name":"query","required":true,"in":"query","schema":{"example":"Lisbon","type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HotelDestinationDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Resolve a place name to something searchable","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/hotels/searches":{"post":{"description":"Answers with hotels and rates once prices have settled. Every rate carries a `rateId` valid for 20 minutes; that is the offer window at the supplier, not a limit we invented.","operationId":"createHotelSearch","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Start a search — billable","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"required"}},"/v1/hotels/searches/{id}":{"get":{"description":"Reads our own cache and costs us nothing, so it never counts.","operationId":"getHotelSearch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Current state of a search — free","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"},"patch":{"description":"Changing dates, destination or occupancy asks the supplier again and counts. Re-sorting or paging does not. `X-Search-Billable` on the response tells you which it was.","operationId":"refineHotelSearch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchPatchDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Refine a search — billable only if it reaches the supplier","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"conditional","x-billable-when-fields-change":["checkIn","checkOut","destination","latitude","longitude","radiusKm","nearPoi","areaHint","adults","children","childrenAges","rooms","currency"],"x-idempotency":"none"}},"/v1/hotels/searches/{id}/load-more":{"post":{"operationId":"loadMoreHotels","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoadMoreDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelSearchDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Fetch more results — billable","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"required"}},"/v1/hotels/{hotelId}/rates":{"get":{"description":"The step between a search result and a booking. The search gives one indicative price per hotel; this asks the supplier what can actually be booked for those dates and returns the `rateId` that `POST /v1/hotels/bookings` expects.\n\nThe price here may differ from the one in the search. That is not a defect — a real availability check happens in between. When it differs materially, `priceNotice` says so instead of quietly showing the higher number.","operationId":"listHotelRates","parameters":[{"name":"hotelId","required":true,"in":"path","schema":{"type":"string"}},{"name":"checkIn","required":false,"in":"query","schema":{"example":"2026-11-02","type":"string"}},{"name":"checkOut","required":false,"in":"query","schema":{"example":"2026-11-06","type":"string"}},{"name":"adults","required":false,"in":"query","schema":{"example":2,"type":"number"}},{"name":"children","required":false,"in":"query","schema":{"type":"number"}},{"name":"rooms","required":false,"in":"query","schema":{"type":"number"}},{"name":"residency","required":false,"in":"query","description":"The guest's country of residence. Some rates are only sold to some markets.","schema":{"example":"de","type":"string"}},{"name":"language","required":false,"in":"query","schema":{"example":"en","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelRatesDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"The bookable rates of one hotel — billable","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"none"}},"/v1/hotels/bookings":{"post":{"description":"We reserve the amount on your account, book with the supplier, then charge what was actually due. If the supplier declines, the reservation is released and you are not charged.","operationId":"createHotelBooking","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHotelBookingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"The balance does not cover this operation (`insufficient_funds`), or the account is not active (`account_not_active`). Do NOT retry — the answer only changes once a top-up happens. `error.availableCents` and `error.requiredCents` name the shortfall, `error.currency` the account's currency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Book a rate — charged to your account","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"},"get":{"description":"Everything you booked through this API, whether or not you kept the reference. Paged with `limit` and `cursor` like every other list here.","operationId":"listHotelBookings","parameters":[{"name":"limit","required":false,"in":"query","schema":{"example":25,"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"From the previous page. Opaque — read it, do not build it.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Your hotel bookings, newest first","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/hotels/bookings/{id}":{"get":{"operationId":"getHotelBooking","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One booking","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/hotels/bookings/{id}/cancel":{"post":{"description":"What it costs follows the `cancellationPolicy` you were given at booking time — we pass the supplier’s terms through verbatim rather than interpreting them.","operationId":"cancelHotelBooking","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelBookingDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HotelBookingDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Cancel a booking","tags":["Hotels"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["hotels:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"}},"/v1/flights/searches":{"post":{"description":"No session, no polling: the response carries the offers. Each `offerId` is valid for 20 minutes.","operationId":"searchFlights","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightSearchDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Search flights — billable, answers immediately","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"required"}},"/v1/flights/offers/{id}":{"get":{"description":"Billable because the airline reprices on this call, which costs us. That is the difference from polling a hotel search, which only reads our own cache.","operationId":"getFlightOffer","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightOfferDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Re-price an offer — billable","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"none"}},"/v1/flights/orders":{"post":{"description":"The airline reprices before booking; that is the rule, not the exception. Set `maxTotalCents` and we refuse above it with `409 price_changed` — nothing booked, nothing charged. Without it we book at the new price and charge what was actually due.","operationId":"createFlightOrder","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFlightOrderDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"The balance does not cover this operation (`insufficient_funds`), or the account is not active (`account_not_active`). Do NOT retry — the answer only changes once a top-up happens. `error.availableCents` and `error.requiredCents` name the shortfall, `error.currency` the account's currency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Book an offer — charged to your account","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"},"get":{"description":"Everything you booked through this API, whether or not you kept the id. Paged with `limit` and `cursor`, the same way as every other list in this contract — pass back `nextCursor` unchanged and stop when it is null. The rows are summaries; the itinerary and the passengers are on the single order.","operationId":"listFlightOrders","parameters":[{"name":"limit","required":false,"in":"query","schema":{"example":25,"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"From the previous page. Opaque — read it, do not build it.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightOrderPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Your flight orders, newest first","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/flights/orders/{id}":{"get":{"operationId":"getFlightOrder","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One order","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/flights/orders/{id}/cancellation-quote":{"get":{"description":"The airline penalty and what would be credited back to your account. A read: it costs nothing, changes nothing, and does not count against your search allowance. Ask it before you show a traveller a number.","operationId":"getFlightCancellationQuote","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightCancellationQuoteDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"What cancelling would cost","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/flights/orders/{id}/cancel":{"post":{"description":"Cancels with the airline and credits the refundable part to your account — never a card refund, because in this channel you are the merchant. Check the quote first: the penalty stays with us and a non-refundable fare credits nothing. If `refundCredited` comes back false the flight IS cancelled and we owe you; do not read it as a failure to retry.","operationId":"cancelFlightOrder","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightCancellationDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Cancel a flight order","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"}},"/v1/flights/orders/{id}/change-options":{"post":{"description":"Name the slice you want to replace and where you want to go instead; you get back priced options, each with a `changeId`. Nothing is reissued and no money moves — but it does cost us a supplier call, so it carries the booking rate limit rather than the read one. `differenceCents` is SIGNED: negative means the new itinerary is cheaper and the difference comes back to you.\n\nWHERE `removeSliceId` COMES FROM: read it from `slices[].id` on the order. `FlightSliceDto` — the slice shape on an offer, on an order and on the options below — publishes the supplier id, so the flow runs search → book → read the order → change, entirely from this API. Before 17.09.2026 no response carried one and this endpoint could not be driven end to end; a `slices[].id` of `null` still means that particular slice has no supplier id and cannot be named in a change request.\n\nEach option carries its own `expiresAt` — the airline deadline, which may be `null` and always is in the sandbox. A `changeId` is additionally one of our handles, so it also dies about twenty minutes after this call: the earlier of the two ends it, and either way a spent option answers `410 offer_expired` on `POST …/change`.","operationId":"listFlightChangeOptions","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightChangeOptionsRequestDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightChangeOptionsDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Priced alternatives for one leg","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"}},"/v1/flights/orders/{id}/change":{"post":{"description":"Takes one `changeId` from the options and reissues. If the change costs money we reserve it against your account BEFORE asking the airline — a rebooking we cannot charge for is one we will not make. If it is cheaper the difference is credited afterwards. `settled: false` means the TICKET IS REISSUED and the money has not moved; it is never a reason to call again.","operationId":"changeFlightOrder","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmFlightChangeDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlightChangeDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"The balance does not cover this operation (`insufficient_funds`), or the account is not active (`account_not_active`). Do NOT retry — the answer only changes once a top-up happens. `error.availableCents` and `error.requiredCents` name the shortfall, `error.currency` the account's currency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Reissue the ticket on a chosen option","tags":["Flights"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["flights:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"}},"/v1/transfers/searches":{"post":{"description":"One call, one answer — there is no session to poll. Each offer carries a `quoteId` valid for about 20 minutes; after that the answer is `410 offer_expired` and you search again.\n\nThis call reaches the supplier and therefore counts against your search allowance. `X-Search-Billable` on the response says whether it did.","operationId":"searchTransfers","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchTransfersDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferSearchResultDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Live transfer availability for a route","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:search"],"x-rate-limit-class":"SEARCH","x-billable-search":"always","x-idempotency":"required"}},"/v1/transfers/orders":{"post":{"description":"Books at the supplier immediately — there is no hold step, so a successful answer is a real booking.\n\nYour account is checked and reserved BEFORE the supplier is contacted, so an insufficient balance costs you nothing. `externalReference` is the idempotency key: repeating a request with the same value returns the same order rather than buying a second transfer, which is what makes a retry after a timeout safe.","operationId":"createTransferOrder","parameters":[{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTransferOrderDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"402":{"description":"The balance does not cover this operation (`insufficient_funds`), or the account is not active (`account_not_active`). Do NOT retry — the answer only changes once a top-up happens. `error.availableCents` and `error.requiredCents` name the shortfall, `error.currency` the account's currency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Book a transfer","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"},"get":{"description":"Everything you booked through this API, whether or not you kept the id. Paged with `limit` and `cursor` like every other list here.","operationId":"listTransferOrders","parameters":[{"name":"limit","required":false,"in":"query","schema":{"example":25,"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"From the previous page. Opaque — read it, do not build it.","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderPageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Your transfer orders, newest first","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/transfers/orders/{orderId}":{"get":{"description":"Poll this while `settlement.funds` is `still_held` — that is the state the reconciliation worker resolves.","operationId":"getTransferOrder","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"One of your transfer orders","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/transfers/orders/{orderId}/cancellation-quote":{"get":{"description":"Computed from the cancellation policy captured when the offer was quoted — the policy your customer saw is the policy that binds. Costs nothing and does not count against your allowance.","operationId":"getTransferCancellationQuote","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferCancellationQuoteDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"What cancelling would cost","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:book"],"x-rate-limit-class":"READ","x-billable-search":false,"x-idempotency":"none"}},"/v1/transfers/orders/{orderId}/cancel":{"post":{"description":"Cancels at the supplier and credits your account with the refundable part — never a card refund, because in this channel you are the merchant. Check the cancellation quote first: the penalty stays with us and a non-refundable rate credits nothing.","operationId":"cancelTransferOrder","parameters":[{"name":"orderId","required":true,"in":"path","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Mandatory on every POST. The same request with the same key returns the stored response without reaching the supplier again. The same key with a DIFFERENT body is rejected with `409 idempotency_key_reuse`. Retained for 24 hours.","required":true,"schema":{"type":"string","maxLength":255,"example":"4f1c358f-6b2e-5acb-8ef5-0c3d0bcc35f5"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferOrderDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"401":{"description":"No key, or an invalid, revoked or expired key, or a valid key sent to the other environment. `error.type` tells them apart: `authentication_required`, `invalid_api_key`, `api_key_revoked`, `api_key_expired`, `wrong_environment`. On `wrong_environment` the key is fine and the base URL is not — a `vcb_live_…` key was sent to the sandbox host or a `vcb_test_…` key to the live host; `error.gatewayEnvironment` names the host, `error.keyEnvironment` the key. Do not rotate the key, change the URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"403":{"description":"The key is not allowed to do this. On `insufficient_scope`, `error.missingScope` names the missing scope; on `ip_not_allowed` the request came from an address outside the allowlist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"409":{"description":"The same idempotency key was used with a different body (`idempotency_key_reuse`), or a request with this key is still in flight (`idempotency_key_in_progress`). The second case may be retried after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"429":{"description":"Quota exhausted. `Retry-After` and `error.retryAfter` give the wait in seconds. This response MAY be retried — after the stated time.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"500":{"description":"A failure on our side. The `requestId` in the response belongs in every support request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}},"503":{"description":"A supplier is unreachable (`upstream_unavailable`). May be retried, with growing backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Upper limit of the class that applied to this request.","schema":{"type":"integer","example":1200}},"X-RateLimit-Remaining":{"description":"Remaining requests in the running window.","schema":{"type":"integer","example":1199}},"X-RateLimit-Reset":{"description":"Unix time at which the window starts anew.","schema":{"type":"integer","example":1788570420}},"X-Request-Id":{"description":"Identifier of this request. Quote it in any support request — including on a successful response, in case the outcome becomes questionable later.","schema":{"type":"string","format":"uuid"}}}}},"summary":"Cancel a transfer order","tags":["Transfers"],"security":[{"partnerApiKey":[]}],"x-required-scopes":["transfers:book"],"x-rate-limit-class":"BOOKING","x-billable-search":false,"x-idempotency":"required"}}},"info":{"title":"Vacabee Partner API","description":"\n  # Vacabee Partner API\n\n  Hotels, flights and eSIM for partners selling in their own systems.\n\n  ## Authentication\n\n  `Authorization: Bearer vcb_live_...` (or `vcb_test_...` for the sandbox).\n  Every endpoint requires a scope; the 403 body names the scope that is missing.\n\n  ## Idempotency\n\n  Every POST requires an `Idempotency-Key` header. Repeating a request with the\n  same key and the same body returns the stored response without reaching a\n  supplier again; the same key with a different body is refused with\n  `409 idempotency_key_reuse`. Records are kept for 24 hours.\n\n  ## Errors\n\n  ```json\n  { \"error\": { \"type\": \"insufficient_scope\", \"message\": \"...\", \"requestId\": \"...\", \"docUrl\": \"...\" } }\n  ```\n\n  Every response carries `X-Request-Id`. Quote it in any support request.\n      ","version":"1.0","contact":{}},"tags":[{"name":"Meta","description":"Reachability, account, permissions and limits"},{"name":"Account","description":"Your prepaid balance, every movement on it, and the free search allowance left for today."},{"name":"Hotels","description":"Resolve a destination, search, read the rates of one hotel, book. Searching is billable; a booking is charged to your account."},{"name":"Flights","description":"Search, re-price the offer you picked, book it. Both search and re-pricing are billable; a booking is charged to your account."},{"name":"Transfers","description":"Airport and point-to-point rides: availability for a route, booking, what a cancellation would cost, and the cancellation itself."},{"name":"eSIM","description":"Coverage by country and region, plans at your net price, and orders with their activation data and live usage."},{"name":"Webhooks","description":"Delivery targets and the history. Needs its own scope `webhooks:manage` — whoever can change targets can redirect the event stream."},{"name":"Health","description":"Operational. Not part of the partner contract."}],"servers":[{"url":"https://api.vacabee.com","description":"Live"},{"url":"https://sandbox-api.vacabee.com","description":"Sandbox — no suppliers, no costs"}],"components":{"securitySchemes":{"partnerApiKey":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Your API key from the partner portal: `Authorization: Bearer vcb_live_...` — or `vcb_test_...` against the sandbox. The gateway checks the key kind against the kind each deployment is configured to accept and refuses a mismatch with `wrong_environment` — but today a single deployment accepts both kinds, so that refusal does not fire yet. It starts to refuse once the two hosts are separate deployments; until then, match the key prefix against the base URL in your own configuration."}},"schemas":{"UpstreamStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error","not_configured"],"example":"ok","description":"`ok` — reachable. `error` — configured but the probe failed; the reason stays in our logs and is deliberately not in this response. `not_configured` — no base URL is configured for this dependency in this deployment, so nothing was probed. On the sandbox host that is the normal answer for all four upstreams: it answers from generated data and has no supplier connections, so it is not an outage and not something to alert on."},"service":{"type":"string","example":"vacabee-profile"},"responseTime":{"type":"number","example":21}},"required":["status","service"]},"TerseHealthDto":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"],"example":"ok"},"service":{"type":"string","example":"vacabee-partner-api"},"timestamp":{"type":"string","format":"date-time","example":"2026-09-05T04:12:33.019Z"}},"required":["status","service","timestamp"]},"DependencyStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error","not_configured"],"example":"ok","description":"`ok` — reachable. `error` — configured but the probe failed; the reason stays in our logs and is deliberately not in this response. `not_configured` — no base URL is configured for this dependency in this deployment, so nothing was probed. On the sandbox host that is the normal answer for all four upstreams: it answers from generated data and has no supplier connections, so it is not an outage and not something to alert on."},"responseTime":{"type":"number","description":"Response time of the check, in milliseconds.","example":7}},"required":["status"]},"FullHealthDto":{"type":"object","properties":{"status":{"type":"string","enum":["ok","error"],"example":"ok"},"service":{"type":"string","example":"vacabee-partner-api"},"timestamp":{"type":"string","format":"date-time","example":"2026-09-05T04:12:33.019Z"},"database":{"$ref":"#/components/schemas/DependencyStatusDto"},"redis":{"$ref":"#/components/schemas/DependencyStatusDto"},"upstreams":{"type":"object","description":"State per downstream service, keyed by the service name — `hotels`, `flights`, `transfers` and `esim`. On the sandbox host all four report `not_configured`, which is expected rather than an outage, and a green sandbox answer here says nothing about live.","additionalProperties":{"$ref":"#/components/schemas/UpstreamStatusDto"},"example":{"profile":{"status":"ok","service":"vacabee-profile","responseTime":21}}}},"required":["status","service","timestamp","database","redis","upstreams"]},"ApiErrorDetailDto":{"type":"object","properties":{"type":{"type":"string","description":"For branching. Stable and machine-readable — a caller may switch on this. New types can be added at any time, so an unknown type must be treated like a generic error.","enum":["authentication_required","invalid_api_key","api_key_revoked","api_key_expired","insufficient_scope","ip_not_allowed","wrong_environment","invalid_request","not_found","method_not_allowed","unsupported_media_type","idempotency_key_required","idempotency_key_reuse","idempotency_key_in_progress","offer_expired","price_changed","insufficient_funds","search_quota_exceeded","account_not_active","not_implemented","settlement_not_allowed","settlement_not_available","rate_limit_exceeded","upstream_unavailable","upstream_error","internal_error"],"example":"insufficient_scope","x-error-catalog":{"authentication_required":{"status":401,"when":"No `Authorization` header, or one the gateway cannot read as a bearer key.","retry":"no","retryNote":"Send the key."},"invalid_api_key":{"status":401,"when":"The key is not one we issued, or its secret does not match.","retry":"no","retryNote":"Check the key you deployed, then issue a new one in the portal."},"api_key_revoked":{"status":401,"when":"The key existed and was switched off in the partner portal.","retry":"no","retryNote":"A revoked key never comes back — issue a new one."},"api_key_expired":{"status":401,"when":"The key is past the expiry date it was issued with.","retry":"no","retryNote":"Issue a new key."},"insufficient_scope":{"status":403,"when":"The key is valid and does not carry the scope this operation needs; `error.missingScope` names it.","retry":"no","retryNote":"Issue a key with that scope — scopes are fixed at issue time."},"ip_not_allowed":{"status":403,"when":"The request came from an address outside the key's allowlist.","retry":"no","retryNote":"Add the address in the portal, or call from an allowed one."},"wrong_environment":{"status":401,"when":"A `vcb_live_…` key was sent to the sandbox host, or a `vcb_test_…` key to the live host.","retry":"no","retryNote":"The key is fine and the base URL is not. Change the URL, do not rotate the key."},"invalid_request":{"status":400,"when":"A malformed body, a failed validation, or a property the endpoint does not know — unknown fields are rejected, not ignored.","retry":"no","retryNote":"Fix the request."},"not_found":{"status":404,"when":"Unknown resource, or an id that belongs to no object of yours.","retry":"no"},"method_not_allowed":{"status":405,"when":"The path exists and does not answer this method.","retry":"no"},"unsupported_media_type":{"status":415,"when":"A body that is not `application/json`.","retry":"no"},"idempotency_key_required":{"status":400,"when":"A POST without `Idempotency-Key`, or a key that is not 8 to 255 printable ASCII characters.","retry":"no","retryNote":"Send a key and keep it for every retry of that same operation."},"idempotency_key_reuse":{"status":409,"when":"The same idempotency key was already used with a different body.","retry":"no","retryNote":"A decision, not a glitch: either resend the original body, or use a new key for the new one."},"idempotency_key_in_progress":{"status":409,"when":"A request with this key is still running.","retry":"yes","retryNote":"After a short wait, with the same key and the same body."},"offer_expired":{"status":410,"when":"A rate, offer or quote handle is past its lifetime of roughly twenty minutes, or is unknown.","retry":"no","retryNote":"Not as sent — search again and re-price. It is deliberately not a 404, which would send you looking for a bug."},"price_changed":{"status":409,"when":"The supplier now prices the offer above the ceiling the request allowed. Nothing was booked.","retry":"no","retryNote":"Only after deciding on the new price: book again with a ceiling that covers it."},"insufficient_funds":{"status":402,"when":"The prepaid balance does not cover this operation. Raised before a supplier is contacted; carries `availableCents` and `requiredCents`.","retry":"no","retryNote":"After a top-up."},"search_quota_exceeded":{"status":429,"when":"The daily search ceiling set for your account has been reached.","retry":"no","retryNote":"Not today — it resets at the time in `error.resetAt`, and the ceiling itself is yours to change in the portal."},"account_not_active":{"status":403,"when":"The account is read-only or suspended.","retry":"no","retryNote":"An invoicing matter, not a key problem — topping up does not help."},"not_implemented":{"status":501,"when":"The operation is real, documented and not available for this key yet. Reserved — nothing raises it today.","retry":"no"},"settlement_not_allowed":{"status":403,"when":"The request asked to settle in a mode this key does not carry. The mode follows the key, not the body.","retry":"no","retryNote":"Use a key issued for that mode."},"settlement_not_available":{"status":501,"when":"The mode is agreed for your account and this gateway cannot execute it — today that is traveller-paid (`vacabee`) settlement.","retry":"no","retryNote":"Nothing was booked, reserved or charged. Book with a key that settles as `partner` until it ships."},"rate_limit_exceeded":{"status":429,"when":"Too many requests in the running window, for this key or from this address.","retry":"yes","retryNote":"After the seconds in `Retry-After` and `error.retryAfter`."},"upstream_unavailable":{"status":503,"when":"A supplier or an internal service did not answer.","retry":"yes","retryNote":"With growing backoff and the original idempotency key. Bounded, not forever."},"upstream_error":{"status":503,"when":"A supplier answered, with a failure or a rejection.","retry":"yes","retryNote":"With backoff — but a rejection does not become an acceptance, so give up early."},"internal_error":{"status":500,"when":"A failure on our side.","retry":"yes","retryNote":"With backoff and the original idempotency key. Quote `requestId` if it persists."}}},"message":{"type":"string","description":"For humans: log lines and support requests. The wording can change at any time — NEVER compare against it.","example":"The key lacks the `hotels:book` scope."},"requestId":{"type":"string","description":"Identifier of this exact request, also in the `X-Request-Id` header. Quote it in every support request: it is how we find the request in our logs.","example":"a4f1c358-6b2e-5acb-8ef5-0c3d0bcc35f5"},"docUrl":{"type":"string","description":"The documentation page that explains this error. Points at the topic, not at one page per error type.","example":"https://developers.vacabee.com/docs/authentication"},"missingScope":{"type":"string","description":"On `insufficient_scope`: the scope that is missing. Saves a caller from having to read it out of the message.","example":"hotels:book"},"retryAfter":{"type":"number","description":"On `rate_limit_exceeded`: seconds until the next permitted attempt. Also present in the `Retry-After` header.","example":12},"violations":{"description":"On `invalid_request` when body validation failed: one line per rejected property, straight from the validator. This is the only part of a 400 that says WHAT was wrong — `message` does not name the property. Log it.","example":["property nights should not exist","adults must not be less than 1"],"type":"array","items":{"type":"string"}},"missingScopes":{"description":"On `insufficient_scope`: every scope the key is missing. `missingScope` is the first entry of this list. No operation requires more than one scope today, so it holds exactly one — branch on the list if you want that to keep being true for you.","example":["hotels:book"],"type":"array","items":{"type":"string"}},"requiredScopes":{"description":"On `insufficient_scope`: every scope the operation requires, whether or not the key has it. Where there is more than one the gateway ANDs them — it is never a choice between them.","example":["hotels:book"],"type":"array","items":{"type":"string"}},"availableCents":{"type":"number","description":"On `insufficient_funds`: what the account can spend right now, so you can render the shortfall rather than the demand alone.","example":4200},"requiredCents":{"type":"number","description":"On `insufficient_funds`: what this operation needs.","example":12600},"currency":{"type":"string","description":"On `insufficient_funds`: the currency both amounts are in — the account's, not the booking's.","example":"USD"},"previousTotalCents":{"type":"number","description":"On `price_changed`: the total the offer carried when you searched. Nothing was booked at either amount.","example":18400},"currentTotalCents":{"type":"number","description":"On `price_changed`: the total the supplier now wants. Show both and decide, or book again with a ceiling that covers it.","example":20900},"accountStatus":{"type":"string","description":"On `account_not_active`: the status that refused the call. `READ_ONLY` still allows reads and cancellations and no new bookings; `SUSPENDED` allows neither. Both are invoicing states — topping up does not clear them.","enum":["READ_ONLY","SUSPENDED"],"example":"READ_ONLY"},"service":{"type":"string","description":"On `upstream_error` and `upstream_unavailable`: which service failed — `hotels`, `flights`, `transfers`, `esim` or `profile`. The two types share a status (503), so this plus `type` is what tells a supplier outage apart from a supplier rejection.","example":"hotels"},"knownTriggers":{"description":"Sandbox only. On an `X-Partner-Customer-Ref` that starts with `sbx_` and is not one of the six failure triggers: all six, so a typo is answered with the list instead of being silently ignored.","example":["sbx_offer_expired","sbx_price_changed","sbx_insufficient_funds","sbx_payment_failed","sbx_supplier_error","sbx_slow"],"type":"array","items":{"type":"string"}}},"required":["type","message","requestId"]},"ApiErrorDto":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ApiErrorDetailDto"}},"required":["error"]},"PingDto":{"type":"object","properties":{"status":{"type":"string","description":"Always `ok` if the response arrives.","example":"ok"},"service":{"type":"string","description":"Which service answered.","example":"vacabee-partner-api"},"timestamp":{"type":"string","description":"Server time in UTC, per ISO 8601. Useful for spotting a clock drift on your own side — that is a common cause of rejected webhook signatures.","example":"2026-09-05T04:12:33.019Z","format":"date-time"}},"required":["status","service","timestamp"]},"AccountPartnerDto":{"type":"object","properties":{"id":{"type":"string","description":"Our identifier for the partner. Stable.","example":"1e4861d9-af96-4821-b264-c1670dbd4b2b","format":"uuid"},"slug":{"type":"string","description":"Short name of the partner, as assigned in the portal.","example":"whitelabeltravel"},"name":{"type":"string","description":"Display name of the partner.","example":"Whitelabel Travel"}},"required":["id","slug"]},"AccountKeyDto":{"type":"object","properties":{"prefix":{"type":"string","description":"The visible part of the key this request came in with. It is shown in the portal as well — so you can tell which of several keys is currently talking.","example":"vcb_test_A8xWTLai"},"environment":{"type":"string","description":"Environment of this key. The gateway compares it against the kind of key the deployment is configured to accept and refuses a mismatch with `wrong_environment` — but today a single deployment accepts both kinds, so that refusal does not fire yet. It starts to refuse once the two hosts are separate deployments; until then, matching the key prefix against the base URL is on the caller (the SDK derives the host from the prefix by itself).","enum":["LIVE","TEST"],"example":"TEST"},"sandbox":{"type":"boolean","description":"Whether this call lands on the sandbox: no suppliers, no costs, no search quota.","example":true},"settlement":{"type":"string","description":"How THIS key settles — who takes the traveller's money for anything bought with it.\n\n`partner`: you are merchant of record. Prices you see are net, your account is charged, your traveller pays you.\n`vacabee`: we are merchant of record. Prices you see are end-customer prices, your traveller pays us, and you earn a commission.\n\nThe mode follows the key, not the request: a key does one of the two and never both. If you run both modes you hold two keys — which is also what makes it unambiguous which price a search result carries. Sending `settlement` in a booking body is allowed and is checked against this value; it cannot change it.","enum":["partner","vacabee"],"example":"partner"}},"required":["prefix","environment","sandbox","settlement"]},"AccountLimitsDto":{"type":"object","properties":{"requestsPerMinute":{"type":"number","description":"Requests per minute across all classes, unless limited more tightly.","example":600},"rateLimitClasses":{"type":"object","description":"Upper bound per class and minute. A search counts differently from a read, because it costs money at the supplier.","example":{"READ":1200,"DEFAULT":600,"SEARCH":120,"BOOKING":60},"additionalProperties":{"type":"number"}},"freeSearchesPerDay":{"type":"number","description":"Billable searches per day that cost nothing. Only calls that actually reach a supplier are counted.","example":1000},"searchHardCapPerDay":{"type":"number","description":"Hard upper bound on searches per day, or `null` for none. Do NOT confuse it with the free quota: beyond that one you are billed, here you are refused.","example":null,"nullable":true},"maxWebsocketConnections":{"type":"number","description":"Concurrent WebSocket connections for the streaming channel.","example":20},"maxWebsocketSubscriptions":{"type":"number","description":"Concurrent subscriptions across all WebSocket connections.","example":200}},"required":["requestsPerMinute","rateLimitClasses","freeSearchesPerDay","searchHardCapPerDay","maxWebsocketConnections","maxWebsocketSubscriptions"]},"AccountDto":{"type":"object","properties":{"partner":{"$ref":"#/components/schemas/AccountPartnerDto"},"key":{"$ref":"#/components/schemas/AccountKeyDto"},"settlementModes":{"description":"Settlement modes your ACCOUNT is set up for — the menu, not the choice. What this particular key does is `key.settlement`, and it is exactly one of these.\n\nA mode listed here that is not your key's is reachable by issuing a key for it, not by asking for it in a request body: a body field that decides who pays would be a permission you write for yourself, and the price it applies to was already formed during the search.","example":["partner","vacabee"],"type":"array","items":{"type":"string"}},"scopes":{"type":"array","description":"What this key may do. A call outside this list is refused with `insufficient_scope` and names the missing scope.","example":["account:read","hotels:search","hotels:book"],"items":{"type":"string","enum":["account:read","hotels:search","hotels:book","flights:search","flights:book","transfers:search","transfers:book","esim:read","esim:order","ledger:read","webhooks:manage","customers:manage"]}},"limits":{"$ref":"#/components/schemas/AccountLimitsDto"},"ipAllowlist":{"description":"IP addresses and networks this key may be used from. Empty means no restriction.","example":[],"type":"array","items":{"type":"string"}}},"required":["partner","key","settlementModes","scopes","limits","ipAllowlist"]},"LedgerBalanceDto":{"type":"object","properties":{"accountId":{"type":"string","example":"acc_4f21"},"accountRef":{"type":"string","example":"VCB-ACC-9K2M","description":"Quote this in a bank transfer so we can match the payment to your account."},"currency":{"type":"string","example":"USD"},"balanceCents":{"type":"number","example":500000,"description":"The sum of every entry on your account. Holds are stored as negative entries, so money already reserved for a booking in flight is ALREADY deducted here."},"creditLimitCents":{"type":"number","example":0,"description":"Agreed overdraft, if you have one."},"heldCents":{"type":"number","example":12400,"description":"How much of the balance is reserved for bookings that have started but not finished. Shown so you can explain the number — NOT to be subtracted again: it is already out of `balanceCents`."},"availableCents":{"type":"number","example":500000,"description":"balance + creditLimit. THE number to check before booking. Holds are not subtracted a second time — they are already inside `balanceCents`."},"status":{"type":"string","example":"ACTIVE","enum":["ACTIVE","SUSPENDED","CLOSED"],"description":"Anything but ACTIVE and bookings answer 402 regardless of the balance."}},"required":["accountId","accountRef","currency","balanceCents","creditLimitCents","heldCents","availableCents","status"]},"LedgerEntryDto":{"type":"object","properties":{"id":{"type":"string","example":"led_8a31"},"kind":{"type":"string","example":"CHARGE","enum":["DEPOSIT","HOLD","RELEASE","CHARGE","REFUND","ADJUSTMENT"]},"amountCents":{"type":"number","example":-12400,"description":"Signed, in minor units. Negative takes money out. The balance is their sum."},"currency":{"type":"string","example":"USD"},"sourceReference":{"type":"string","example":"hotel:e2e-1788707669","description":"Your reference for the thing that caused this. Use it to reconcile."},"description":{"type":"string","example":"Hotel htl_4b21 2026-11-02","nullable":true},"createdAt":{"type":"string","example":"2026-09-06T14:31:09.272Z"}},"required":["id","kind","amountCents","currency","sourceReference","description","createdAt"]},"LedgerEntryPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LedgerEntryDto"}},"nextCursor":{"type":"string","example":null,"nullable":true}},"required":["items","nextCursor"]},"SearchQuotaDto":{"type":"object","properties":{"day":{"type":"string","example":"2026-09-10","description":"The calendar day this counter belongs to, in YOUR time zone. The allowance resets by your day, not by UTC."},"timezone":{"type":"string","example":"Europe/Berlin"},"limit":{"type":"number","example":1000,"description":"Your free searches per day, from your commercial terms."},"used":{"type":"number","example":312,"description":"Billable searches counted today — INCLUDING any above the allowance. Only calls that reach a supplier count; polling, reads and everything in the sandbox do not."},"remaining":{"type":"number","example":688,"description":"How much of the free allowance is left. Never negative: past the allowance it is 0 and `used` keeps climbing."},"reset":{"type":"string","example":"2026-09-11T00:00:00.000Z","description":"When the counter goes back to zero."},"hardCap":{"type":"number","example":null,"nullable":true,"description":"Your own ceiling, if you set one. There is no ceiling from our side — past the free allowance you keep searching and pay. A cap is only ever yours, which is why a search we turned away is counted separately."},"rejected":{"type":"number","example":0,"description":"Searches YOUR hard cap turned away today. Zero unless you set a cap."}},"required":["day","timezone","limit","used","remaining","reset","hardCap","rejected"]},"EsimCountryDto":{"type":"object","properties":{"code":{"type":"string","example":"DE","description":"ISO 3166-1 alpha-2."},"name":{"type":"string","example":"Germany"},"flag":{"type":"string","example":"🇩🇪","nullable":true,"description":"Flag emoji, when we have one."}},"required":["code","name","flag"]},"EsimRegionDto":{"type":"object","properties":{"id":{"type":"string","example":"reg_eu"},"code":{"type":"string","example":"EU"},"name":{"type":"string","example":"Europe"}},"required":["id","code","name"]},"EsimPlanDto":{"type":"object","properties":{"id":{"type":"string","example":"plan_7f3a2b"},"providerPlanId":{"type":"string","example":"plan_7f3a2b","description":"The provider's own identifier."},"name":{"type":"string","example":"Europe 10 GB / 30 days"},"planType":{"type":"string","enum":["data","unlimited","voice_sms"],"example":"data"},"dataAmountMb":{"type":"number","example":10240,"description":"Included data in megabytes."},"validityDays":{"type":"number","example":30},"voiceSeconds":{"type":"number","example":null,"nullable":true},"smsCount":{"type":"number","example":null,"nullable":true},"isGlobal":{"type":"boolean","example":false},"countries":{"type":"array","items":{"$ref":"#/components/schemas/EsimCountryDto"}},"regions":{"type":"array","items":{"$ref":"#/components/schemas/EsimRegionDto"}},"retailCents":{"type":"number","example":4200,"description":"YOUR price in minor units — the net price after your margin, not the consumer price. This is what we charge your account when you order."},"currency":{"type":"string","example":"usd"}},"required":["id","providerPlanId","name","planType","dataAmountMb","validityDays","voiceSeconds","smsCount","isGlobal","countries","regions","retailCents","currency"]},"EsimPlanPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EsimPlanDto"}},"total":{"type":"number","example":42},"page":{"type":"number","example":1},"pageSize":{"type":"number","example":25},"totalPages":{"type":"number","example":2}},"required":["items","total","page","pageSize","totalPages"]},"EsimCustomerDto":{"type":"object","properties":{"firstName":{"type":"string","example":"Ada"},"lastName":{"type":"string","example":"Lovelace"},"email":{"type":"string","example":"ada@example.com","description":"YOUR customer's address. We send him nothing — it goes to the supplier, who issues the eSIM against it."},"phone":{"type":"string","example":"+4915112345678"}},"required":["firstName","lastName","email"]},"CreateEsimOrderDto":{"type":"object","properties":{"planId":{"type":"string","example":"plan_01J8…"},"quantity":{"type":"number","example":1,"minimum":1},"externalReference":{"type":"string","example":"order-2026-0915-abc","description":"YOUR reference for this order. It is the idempotency across the whole operation: the same value twice yields ONE order, not two — even when the first response never reached you."},"customer":{"$ref":"#/components/schemas/EsimCustomerDto"},"settlement":{"type":"string","enum":["partner","vacabee"],"description":"Optional. Who takes the traveller’s money for this order. The mode follows your API KEY — sending it here is a check, not a choice: a value that contradicts your key is refused rather than obeyed."}},"required":["planId","externalReference","customer"]},"EsimCheckoutDto":{"type":"object","properties":{"url":{"type":"string","nullable":true,"example":"https://mrbee.ai/pay/8Kx…","description":"Send your traveller here. The link is issued ONCE and is never stored, by us or by anyone: repeat the same `externalReference` and you get the order back with `url: null` and the deadline of the link you already have. Keep it when you receive it."},"expiresAt":{"type":"string","example":"2026-09-10T12:15:00.000Z","description":"When the link stops being payable. Running out is the ORDINARY outcome of an unpaid order, not a fault: nothing is reserved for your traveller, the price simply expires. You then get `esim.failed` with reason `checkout_expired` and can order again at the price of the day."},"amountCents":{"type":"number","example":4200,"description":"What YOUR TRAVELLER pays, in minor units — the end-customer price. Not a net price: in this mode you buy nothing from us."},"currency":{"type":"string","example":"usd"}},"required":["url","expiresAt","amountCents","currency"]},"EsimOrderDto":{"type":"object","properties":{"purchaseId":{"type":"string","example":"pur_01J8…"},"netAmountCents":{"type":"number","example":1080,"description":"What YOU owe us for this order — your purchase price. What you charge your own customer is your business and we do not see it.\n\n`0` when this order settles as `vacabee`: there your traveller pays us directly and you owe us nothing at all. What HE pays is in `checkout.amountCents`."},"currency":{"type":"string","example":"usd"},"status":{"type":"string","enum":["ACTIVE","PENDING","AWAITING_PAYMENT"],"description":"ACTIVE means: the eSIM is provisioned at the supplier.\n\nAWAITING_PAYMENT appears only in `vacabee` settlement and means exactly what it says — the order is written down, NOTHING has been bought, and nothing will be until your traveller has paid through `checkout.url`."},"provisioningStatus":{"type":"string","example":"provisioned"},"iccid":{"type":"string","nullable":true,"example":"89310…"},"activationCode":{"type":"string","nullable":true,"example":"LPA:1$smdp.example$ABC"},"lpaCode":{"type":"string","nullable":true},"smdpAddress":{"type":"string","nullable":true},"qrCodeUrl":{"type":"string","nullable":true,"example":"https://…/qr.png"},"settlement":{"type":"string","enum":["partner","vacabee"],"description":"How this order settles — echoed back so you never have to infer it. It follows your API KEY; see /docs/settlement."},"checkout":{"nullable":true,"description":"Where your traveller pays. `null` in `partner` settlement, where the order is already paid for out of your account.","type":"object","allOf":[{"$ref":"#/components/schemas/EsimCheckoutDto"}]}},"required":["purchaseId","netAmountCents","currency","status","provisioningStatus","iccid","activationCode","lpaCode","smdpAddress","qrCodeUrl","settlement","checkout"]},"EsimOrderPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/EsimOrderDto"}},"nextCursor":{"type":"string","example":null,"nullable":true,"description":"Pass as `cursor` to get the next page. `null` means this was the last one."}},"required":["items","nextCursor"]},"EsimUsageDto":{"type":"object","properties":{"dataUsedMb":{"type":"number","nullable":true,"example":1024},"dataRemainingMb":{"type":"number","nullable":true,"example":9216},"dataTotalMb":{"type":"number","nullable":true,"example":10240},"status":{"type":"string","nullable":true,"description":"Null means: the supplier was briefly unreachable and you are seeing the last known state."},"expiresAt":{"type":"string","nullable":true,"description":"The end date, when the supplier has given us one. Frequently `null`: many plans get no date until the profile is activated. Do not read `null` as \"never expires\" — read `expired`."},"expired":{"type":"boolean","description":"Our own verdict on the profile at the time of the call. Prefer it over comparing `expiresAt` with your clock: a profile counts as expired once the supplier reports it as finished or once its data is used up, both of which happen before any printed date — and it is `false` while the profile is not provisioned yet, even past that date."}},"required":["dataUsedMb","dataRemainingMb","dataTotalMb","status","expiresAt","expired"]},"WebhookEndpointDto":{"type":"object","properties":{"id":{"type":"string","example":"ep_01J8…"},"url":{"type":"string","example":"https://api.example.com/hooks/vacabee"},"events":{"type":"array","items":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked"]}},"secretPrefix":{"type":"string","example":"whsec_LL2z9E","description":"Only the beginning of the signing secret, so that you can tell two endpoints apart. The full value appears exactly once: on creation and on rotation."},"status":{"type":"string","enum":["ACTIVE","DISABLED"]},"description":{"type":"string","nullable":true},"lastDeliveryAt":{"type":"string","nullable":true,"example":"2026-09-05T09:12:44.000Z"},"createdAt":{"type":"string","example":"2026-08-30T11:02:00.000Z"},"canDeliver":{"type":"boolean","description":"False for endpoints predating delivery: for those we only hold a hash of the secret, and you cannot sign with a hash. Such endpoints receive nothing until the secret has been rotated once."}},"required":["id","url","events","secretPrefix","status","description","lastDeliveryAt","createdAt","canDeliver"]},"CreateWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","example":"https://api.example.com/hooks/vacabee","description":"https, and the host must resolve publicly. A target inside a private network would make us query internal services from within our own cluster and deliver the answer to you."},"events":{"type":"array","example":["booking.confirmed","payment.refunded"],"description":"An unknown event is refused rather than accepted: a subscription to something nobody publishes looks like coverage and is silence.","items":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked"]}},"description":{"type":"string","example":"Production consumer","maxLength":200}},"required":["url","events"]},"CreatedWebhookEndpointDto":{"type":"object","properties":{"endpoint":{"$ref":"#/components/schemas/WebhookEndpointDto"},"signingSecret":{"type":"string","example":"whsec_LL2z9ESy…","description":"THE ONLY TIME you get to see this value. It is the only thing that tells a genuine delivery apart from any other POST to your public endpoint. Lost it? Then rotate — do not ask us for it."},"signingSecretShownOnce":{"type":"boolean","example":true},"previousSecretValidUntil":{"type":"string","nullable":true,"description":"On rotation only: up to this point we ALSO sign with the previous secret, so you can switch over without losing an event."}},"required":["endpoint","signingSecret","signingSecretShownOnce"]},"PatchWebhookEndpointDto":{"type":"object","properties":{"url":{"type":"string","example":"https://api.example.com/hooks/v2"},"events":{"type":"array","items":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked"]}},"description":{"type":"string","maxLength":200},"status":{"type":"string","enum":["ACTIVE","DISABLED"],"description":"DISABLED stops delivery without deleting the endpoint and its history — for a planned maintenance window."}}},"RotateWebhookSecretDto":{"type":"object","properties":{"immediate":{"type":"boolean","default":false,"description":"Kill the previous secret NOW instead of keeping it valid for 24 hours. Only for a leak: without the overlap, every delivery between this call and your deployment fails your signature check. Rotating twice within the overlap is refused unless you set this — the second rotation would silently invalidate a secret we promised would stay valid."}}},"WebhookAttemptDto":{"type":"object","properties":{"id":{"type":"string"},"attemptNumber":{"type":"number","example":3,"description":"Which attempt this is, counted from 1."},"startedAt":{"type":"string","example":"2026-09-05T09:12:44.000Z"},"durationMs":{"type":"number","example":842},"requestHeaders":{"type":"object","nullable":true,"additionalProperties":{"type":"string"},"description":"The headers of THIS attempt, signature included. It differs in every attempt because it is computed over a fresh timestamp — with the old one the retry would fail your replay window."},"statusCode":{"type":"number","nullable":true,"example":500,"description":"Null means: no response arrived at all (timeout, DNS, connection)."},"responseBody":{"type":"string","nullable":true,"description":"Truncated to 4096 characters — somebody else's response is unbounded in length."},"responseHeaders":{"type":"object","nullable":true,"additionalProperties":{"type":"string"}},"error":{"type":"string","nullable":true},"manual":{"type":"boolean","description":"Was this attempt triggered by hand?"},"triggeredBy":{"type":"string","nullable":true}},"required":["id","attemptNumber","startedAt","durationMs","requestHeaders","statusCode","responseBody","responseHeaders","error","manual","triggeredBy"]},"WebhookDeliveryDetailDto":{"type":"object","properties":{"id":{"type":"string","example":"dl_01J8…"},"eventType":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked","webhook.test"]},"eventId":{"type":"string","example":"bk_01J8…","description":"The business ID of what triggered this — your booking, your refund."},"status":{"type":"string","enum":["PENDING","SUCCEEDED","FAILED","EXHAUSTED"],"description":"PENDING is waiting for the next automatic attempt. EXHAUSTED means: the automatic attempts are used up — nothing more happens on its own, but it can still be retried by hand. FAILED means: your endpoint answered 410 Gone, and we stopped instead of calling again."},"attemptCount":{"type":"number","example":3},"nextAttemptAt":{"type":"string","nullable":true},"lastStatusCode":{"type":"number","nullable":true,"example":503},"lastError":{"type":"string","nullable":true},"lastAttemptAt":{"type":"string","nullable":true},"succeededAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"endpoint":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"url":{"type":"string","nullable":true},"description":{"type":"string","nullable":true}}},"retryable":{"type":"boolean","description":"Sending a successful delivery again would create a second event on your side — which is why it is not retryable."},"payload":{"type":"object","description":"Byte for byte what we sent. A retry sends exactly that again, not a freshly serialized version of it."},"attempts":{"type":"array","items":{"$ref":"#/components/schemas/WebhookAttemptDto"}}},"required":["id","eventType","eventId","status","attemptCount","nextAttemptAt","lastStatusCode","lastError","lastAttemptAt","succeededAt","createdAt","endpoint","retryable","payload","attempts"]},"WebhookTestResultDto":{"type":"object","properties":{"delivered":{"type":"boolean"},"delivery":{"$ref":"#/components/schemas/WebhookDeliveryDetailDto"}},"required":["delivered"]},"WebhookDeliveryDto":{"type":"object","properties":{"id":{"type":"string","example":"dl_01J8…"},"eventType":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked","webhook.test"]},"eventId":{"type":"string","example":"bk_01J8…","description":"The business ID of what triggered this — your booking, your refund."},"status":{"type":"string","enum":["PENDING","SUCCEEDED","FAILED","EXHAUSTED"],"description":"PENDING is waiting for the next automatic attempt. EXHAUSTED means: the automatic attempts are used up — nothing more happens on its own, but it can still be retried by hand. FAILED means: your endpoint answered 410 Gone, and we stopped instead of calling again."},"attemptCount":{"type":"number","example":3},"nextAttemptAt":{"type":"string","nullable":true},"lastStatusCode":{"type":"number","nullable":true,"example":503},"lastError":{"type":"string","nullable":true},"lastAttemptAt":{"type":"string","nullable":true},"succeededAt":{"type":"string","nullable":true},"createdAt":{"type":"string"},"endpoint":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"url":{"type":"string","nullable":true},"description":{"type":"string","nullable":true}}},"retryable":{"type":"boolean","description":"Sending a successful delivery again would create a second event on your side — which is why it is not retryable."}},"required":["id","eventType","eventId","status","attemptCount","nextAttemptAt","lastStatusCode","lastError","lastAttemptAt","succeededAt","createdAt","endpoint","retryable"]},"WebhookDeliveryListDto":{"type":"object","properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryDto"}},"nextCursor":{"type":"string","nullable":true,"description":"Pass on as `cursor` to fetch the next page. Null = end."},"deliveryEnabled":{"type":"boolean","description":"False means: nothing is going out on OUR side right now. Events are still being recorded and will go out as soon as it is switched on. This is not a configuration error on your side. It is nothing you can set — it reflects whether our dispatcher has a usable signing key, which is also why `POST /v1/webhooks/endpoints` answers `503 upstream_error` while it is false. Treat every delivery-dependent flow as untestable until it is true, and do not retry; nothing of yours is wrong."}},"required":["deliveries","nextCursor","deliveryEnabled"]},"WebhookRetryResultDto":{"type":"object","properties":{"delivered":{"type":"boolean","description":"Did your endpoint answer with a 2xx this time?"},"delivery":{"$ref":"#/components/schemas/WebhookDeliveryDetailDto"}},"required":["delivered","delivery"]},"HotelDestinationDto":{"type":"object","properties":{"id":{"type":"string","example":"dst_lisbon"},"name":{"type":"string","example":"Lisbon"},"type":{"type":"string","example":"city","enum":["city","region","poi","hotel"]},"country":{"type":"string","example":"PT","description":"ISO 3166-1 alpha-2."}},"required":["id","name","type","country"]},"HotelSearchRequestDto":{"type":"object","properties":{"destination":{"type":"string","example":"Lisbon","description":"Where to search. Either this, `nearPoi`, or a `latitude`/`longitude` pair — without one of the three there is nothing to anchor the search on."},"nearPoi":{"type":"string","example":"Torre de Belém","description":"A landmark to search around. Useful for small places a city name would miss."},"areaHint":{"type":"string","example":"Alfama","description":"A district within the destination."},"latitude":{"type":"number","example":38.7223},"longitude":{"type":"number","example":-9.1393},"radiusKm":{"type":"number","example":5,"description":"Radius around the coordinates, in kilometres."},"checkIn":{"type":"string","example":"2026-11-02","description":"ISO date. Without dates you get availability without prices."},"checkOut":{"type":"string","example":"2026-11-06"},"adults":{"type":"number","example":2,"default":2},"children":{"type":"number","example":0},"childrenAges":{"example":[7,11],"description":"One age per child, as integers — one entry per `children`. Required by most suppliers to price a room correctly.","type":"array","items":{"type":"number"}},"rooms":{"type":"number","example":1,"default":1},"board":{"type":"string","enum":["any","room_only","breakfast","half_board","full_board","all_inclusive"]},"budgetMaxPerNight":{"type":"number","example":20000,"description":"Upper bound per night, in minor units."},"currency":{"type":"string","example":"USD","default":"USD","description":"Display preference only. Every amount this API returns is binding in USD, and every partner account is settled in USD — a booking is charged in the currency of the offer, which this field does not change. It said `EUR` here, which read as a promise we never made and cannot keep: the ledger does not convert, so an amount in anything else is refused rather than exchanged."},"starMin":{"type":"number","example":4,"description":"Minimum star rating."},"amenities":{"example":["wifi","parking"],"type":"array","items":{"type":"string"}},"sort":{"type":"string","example":"price_asc"},"language":{"type":"string","example":"en","default":"en"},"limit":{"type":"number","example":20,"default":20,"description":"At most 100."}}},"HotelPriceFromDto":{"type":"object","properties":{"totalCents":{"type":"number","example":49600,"nullable":true,"description":"For the whole stay."},"perNightCents":{"type":"number","example":12400,"nullable":true},"currency":{"type":"string","example":"USD","nullable":true}},"required":["totalCents","perNightCents","currency"]},"HotelHitDto":{"type":"object","properties":{"hotelId":{"type":"string","example":"htl_4b21","nullable":true},"name":{"type":"string","example":"Altis Avenida Hotel","nullable":true},"starRating":{"type":"number","example":5,"nullable":true,"description":"Star category, 0–5. Never a review score."},"address":{"type":"string","example":"Rua 1º De Dezembro, 120, Lisbon","nullable":true,"description":"One line, as the supplier states it. We do not split it into city and country — that would be guessing, and a guessed address is worse than an undivided one."},"latitude":{"type":"number","example":38.72,"nullable":true},"longitude":{"type":"number","example":-9.14,"nullable":true},"images":{"type":"array","items":{"type":"string"}},"amenities":{"example":["Free Wi-Fi","Parking"],"type":"array","items":{"type":"string"}},"priceFrom":{"nullable":true,"description":"An indicative \"from\" price. NOT bookable — call GET /v1/hotels/{hotelId}/rates for rates you can book.","type":"object","allOf":[{"$ref":"#/components/schemas/HotelPriceFromDto"}]},"rateStatus":{"type":"string","example":"available","enum":["available","checking","none"],"nullable":true,"description":"`available` — there are bookable rates, go fetch them. `checking` — the supplier's price query is still running. `none` — nothing to be had for these dates."},"reviewScore":{"type":"number","example":8.4,"nullable":true,"description":"Guest review score, 0–10. Absent means no reviews — never substituted."},"reviewCount":{"type":"number","example":214,"nullable":true,"description":"How many reviews the score is made of. A score without it is not a verdict."}},"required":["hotelId","name","starRating","address","latitude","longitude","images","amenities","priceFrom","rateStatus","reviewScore","reviewCount"]},"HotelSearchDto":{"type":"object","properties":{"searchId":{"type":"string","example":"ses_7a1f","nullable":true,"description":"Pass to GET/PATCH /v1/hotels/searches/{id} to refine or page."},"status":{"type":"string","example":"complete","description":"`complete` means every supplier answered. A partial result still carries hotels — show them rather than waiting."},"hotels":{"type":"array","items":{"$ref":"#/components/schemas/HotelHitDto"}}},"required":["searchId","status","hotels"]},"HotelSearchPatchDto":{"type":"object","properties":{"destination":{"type":"string","example":"Lisbon","description":"Where to search. Either this, `nearPoi`, or a `latitude`/`longitude` pair — without one of the three there is nothing to anchor the search on."},"nearPoi":{"type":"string","example":"Torre de Belém","description":"A landmark to search around. Useful for small places a city name would miss."},"areaHint":{"type":"string","example":"Alfama","description":"A district within the destination."},"latitude":{"type":"number","example":38.7223},"longitude":{"type":"number","example":-9.1393},"radiusKm":{"type":"number","example":5,"description":"Radius around the coordinates, in kilometres."},"checkIn":{"type":"string","example":"2026-11-02","description":"ISO date. Without dates you get availability without prices."},"checkOut":{"type":"string","example":"2026-11-06"},"adults":{"type":"number","example":2,"default":2},"children":{"type":"number","example":0},"childrenAges":{"example":[7,11],"description":"One age per child, as integers — one entry per `children`. Required by most suppliers to price a room correctly.","type":"array","items":{"type":"number"}},"rooms":{"type":"number","example":1,"default":1},"board":{"type":"string","enum":["any","room_only","breakfast","half_board","full_board","all_inclusive"]},"budgetMaxPerNight":{"type":"number","example":20000,"description":"Upper bound per night, in minor units."},"currency":{"type":"string","example":"USD","default":"USD","description":"Display preference only. Every amount this API returns is binding in USD, and every partner account is settled in USD — a booking is charged in the currency of the offer, which this field does not change. It said `EUR` here, which read as a promise we never made and cannot keep: the ledger does not convert, so an amount in anything else is refused rather than exchanged."},"starMin":{"type":"number","example":4,"description":"Minimum star rating."},"amenities":{"example":["wifi","parking"],"type":"array","items":{"type":"string"}},"sort":{"type":"string","example":"price_asc"},"language":{"type":"string","example":"en","default":"en"},"limit":{"type":"number","example":20,"default":20,"description":"At most 100."}}},"LoadMoreDto":{"type":"object","properties":{"limit":{"type":"number","example":20,"description":"How many more results to add."}}},"HotelCancellationPolicyDto":{"type":"object","properties":{"from":{"type":"string","example":"2026-11-01T18:00:00","nullable":true,"description":"From when this window applies."},"until":{"type":"string","example":"2026-11-02T14:00:00","nullable":true,"description":"Until when."},"chargeCents":{"type":"number","example":11340,"nullable":true,"description":"What cancelling in this window costs, in minor units — at YOUR net basis."}},"required":["from","until","chargeCents"]},"HotelRateDetailDto":{"type":"object","properties":{"rateId":{"type":"string","example":"rate_9f2c1a","description":"Pass to POST /v1/hotels/bookings. Expires — a stale rate answers 410 offer_expired rather than booking at a price that no longer holds."},"roomName":{"type":"string","example":"Double Room","nullable":true},"boardType":{"type":"string","example":"breakfast","nullable":true},"totalCents":{"type":"number","example":12400,"nullable":true,"description":"YOUR net price for the whole stay."},"currency":{"type":"string","example":"USD","nullable":true},"refundable":{"type":"boolean","example":true,"nullable":true,"description":"`null` means we do not know — not \"no\". \"Non-refundable\" is a statement with money behind it, and guessing it is the wrong way to be helpful."},"freeCancellationUntil":{"type":"string","example":"2026-11-01T18:00:00","nullable":true,"description":"Free cancellation up to this moment, when the supplier states one. Local time at the property, as they state it."},"cancellationPolicies":{"description":"Every window the supplier states, in full. We do NOT condense them into one sentence: money hangs on them, and a summary would be our reading rather than the supplier's.","type":"array","items":{"$ref":"#/components/schemas/HotelCancellationPolicyDto"}}},"required":["rateId","roomName","boardType","totalCents","currency","refundable","freeCancellationUntil","cancellationPolicies"]},"HotelRatesDto":{"type":"object","properties":{"hotelId":{"type":"string","example":"htl_4b21"},"rates":{"type":"array","items":{"$ref":"#/components/schemas/HotelRateDetailDto"}},"priceNotice":{"type":"object","nullable":true,"description":"Present ONLY when the price here differs materially from the one the search advertised. Show both numbers rather than quietly using the higher one."}},"required":["hotelId","rates","priceNotice"]},"GuestDto":{"type":"object","properties":{"firstName":{"type":"string","example":"Ada"},"lastName":{"type":"string","example":"Lovelace"},"age":{"type":"number","example":8,"description":"A child's age. Suppliers price children by age, so leave it off for adults."}},"required":["firstName","lastName"]},"ContactDto":{"type":"object","properties":{"email":{"type":"string","example":"ada@example.com"},"phone":{"type":"string","example":"+4915112345678"}},"required":["email"]},"CreateHotelBookingDto":{"type":"object","properties":{"rateId":{"type":"string","example":"rate_8f2c…","description":"From a search result. Valid for 20 minutes — after that `410 offer_expired`, and you search again. The window is how long the offer is valid at the provider, not a limit we set."},"externalReference":{"type":"string","example":"booking-2026-0915-abc","description":"YOUR reference. Idempotency across the whole operation: the same value twice yields ONE booking — even when the first response never reached you."},"guests":{"description":"One entry per guest — as many as the rate is for. A rate for two adults and a child needs three names; naming fewer is refused rather than padded, because an invented name ends up on an invoice and at a hotel desk. Pass `age` for a child. With several rooms the guests are placed in the order given.","type":"array","items":{"$ref":"#/components/schemas/GuestDto"}},"contact":{"$ref":"#/components/schemas/ContactDto"},"specialRequests":{"type":"string","maxLength":500},"settlement":{"type":"string","enum":["partner","vacabee"],"description":"Optional. Who takes the traveller’s money for this booking. The mode follows your API KEY — sending it here is a check, not a choice: a value that contradicts your key is refused rather than obeyed."}},"required":["rateId","externalReference","guests","contact"]},"HotelBookingDto":{"type":"object","properties":{"bookingId":{"type":"string","example":"bkg_31f0","nullable":true},"externalReference":{"type":"string","example":"my-order-4711","nullable":true,"description":"The externalReference you sent when creating this booking."},"status":{"type":"string","example":"CONFIRMED","nullable":true},"hotelName":{"type":"string","example":"Hotel Lisboa Centro","nullable":true},"checkIn":{"type":"string","example":"2026-11-02","nullable":true},"checkOut":{"type":"string","example":"2026-11-06","nullable":true},"totalAmountCents":{"type":"number","example":12400,"nullable":true},"currency":{"type":"string","example":"USD","nullable":true},"confirmationNumber":{"type":"string","example":"conf_88ab","nullable":true},"cancellationPolicy":{"type":"string","nullable":true,"description":"Verbatim, as in the rate."},"guests":{"type":"array","items":{"type":"object"}}},"required":["bookingId","externalReference","status","hotelName","checkIn","checkOut","totalAmountCents","currency","confirmationNumber","cancellationPolicy","guests"]},"HotelBookingPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/HotelBookingDto"}},"nextCursor":{"type":"string","example":null,"nullable":true}},"required":["items","nextCursor"]},"CancelBookingDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}}},"FlightSearchRequestDto":{"type":"object","properties":{"origin":{"type":"string","example":"LHR","description":"IATA code of the departure airport."},"destination":{"type":"string","example":"JFK"},"departureDate":{"type":"string","example":"2026-11-15","description":"ISO date."},"returnDate":{"type":"string","example":"2026-11-22","description":"Omit for a one-way."},"adults":{"type":"number","example":1,"default":1},"children":{"type":"number","example":0},"infants":{"type":"number","example":0,"description":"Infants without their own seat."},"cabinClass":{"type":"string","enum":["economy","premium_economy","business","first"]},"maxConnections":{"type":"number","example":1,"description":"0 means direct flights only."},"airlines":{"type":"string","example":"BA,LH","description":"Comma-separated IATA airline codes."},"sort":{"type":"string","example":"price"}},"required":["origin","destination","departureDate"]},"FlightSliceDto":{"type":"object","properties":{"id":{"type":"string","nullable":true,"example":"sbx_sli_hT2mQ1xR9vL4aZ0c","description":"Pass this as `removeSliceId` to change-options. Null when the supplier did not give the slice an id of its own."},"origin":{"type":"string","example":"LHR"},"destination":{"type":"string","example":"JFK"},"departure":{"type":"string","example":"2026-11-15T08:00:00Z"},"arrival":{"type":"string","example":"2026-11-15T16:30:00Z"},"durationMinutes":{"type":"number","example":510},"stops":{"type":"number","example":0}},"required":["id","origin","destination","departure","arrival","durationMinutes","stops"]},"FlightOfferDto":{"type":"object","properties":{"offerId":{"type":"string","example":"off_2c7d","description":"Stable: the same flight carries the same id across two searches, so you can tell it is the same offer. Pass it to POST /v1/flights/orders."},"totalCents":{"type":"number","example":42000,"nullable":true,"description":"YOUR net price."},"currency":{"type":"string","example":"USD","nullable":true},"slices":{"type":"array","items":{"$ref":"#/components/schemas/FlightSliceDto"}},"airline":{"type":"object","nullable":true,"example":{"iataCode":"BA","name":"British Airways"}},"cabinClass":{"type":"string","example":"economy","nullable":true},"conditions":{"type":"object","nullable":true,"description":"Change and refund rules, VERBATIM. A legal consequence, not a display string.","example":{"changeBeforeDeparture":{"allowed":true,"penaltyCents":5000},"refundBeforeDeparture":{"allowed":false,"penaltyCents":null}}},"baggage":{"type":"object","nullable":true,"example":{"carryOn":1,"checked":0}}},"required":["offerId","totalCents","currency","slices","airline","cabinClass","conditions","baggage"]},"FlightSearchDto":{"type":"object","properties":{"offers":{"type":"array","items":{"$ref":"#/components/schemas/FlightOfferDto"}}},"required":["offers"]},"TravellerDto":{"type":"object","properties":{"firstName":{"type":"string","example":"Ada"},"lastName":{"type":"string","example":"Lovelace"},"dateOfBirth":{"type":"string","example":"1990-05-17","description":"ISO date. Most airlines require it; without it the order can be rejected."},"gender":{"type":"string","example":"f","description":"As the airline records it. Pass through what your customer stated."},"title":{"type":"string","example":"mr","description":"Salutation as the airline records it — mr, ms, mrs, miss, dr. Optional here and required by most carriers: leaving it out answers \"Each passenger must include 'title'\" from the airline."}},"required":["firstName","lastName"]},"CreateFlightOrderDto":{"type":"object","properties":{"offerId":{"type":"string","example":"off_8f2c…"},"externalReference":{"type":"string","example":"order-2026-0915-abc"},"passengers":{"description":"One entry per traveller, as the airline needs them.","type":"array","items":{"$ref":"#/components/schemas/TravellerDto"}},"contact":{"$ref":"#/components/schemas/ContactDto"},"maxTotalCents":{"type":"number","example":45000,"description":"Upper limit. Airlines REPRICE an offer before booking — that is the rule, not the exception. If the new price is above it, NOTHING is booked and nothing is charged; you get `409 price_changed` with both amounts and decide yourself. Without this value we book at the new price."},"settlement":{"type":"string","enum":["partner","vacabee"],"description":"Optional. Who takes the traveller’s money for this order. The mode follows your API KEY — sending it here is a check, not a choice."}},"required":["offerId","externalReference","passengers","contact"]},"FlightOrderDto":{"type":"object","properties":{"orderId":{"type":"string","example":"ord_5a11","nullable":true},"externalReference":{"type":"string","example":"my-order-4711","nullable":true,"description":"The externalReference you sent when creating this booking."},"status":{"type":"string","example":"CONFIRMED","nullable":true},"pnr":{"type":"string","example":"X7QK2P","nullable":true,"description":"The airline record locator."},"totalAmountCents":{"type":"number","example":42000,"nullable":true},"currency":{"type":"string","example":"USD","nullable":true},"slices":{"type":"array","items":{"$ref":"#/components/schemas/FlightSliceDto"}},"passengers":{"type":"array","items":{"type":"object"}},"conditions":{"type":"object","nullable":true,"description":"Verbatim, as in the offer."}},"required":["orderId","externalReference","status","pnr","totalAmountCents","currency","slices","passengers","conditions"]},"FlightOrderSummaryDto":{"type":"object","properties":{"orderId":{"type":"string","example":"ord_5a11","nullable":true},"status":{"type":"string","example":"CONFIRMED","nullable":true},"pnr":{"type":"string","example":"X7QK2P","nullable":true},"totalAmountCents":{"type":"number","example":42000,"nullable":true},"currency":{"type":"string","example":"USD","nullable":true},"createdAt":{"type":"string","nullable":true}},"required":["orderId","status","pnr","totalAmountCents","currency","createdAt"]},"FlightOrderPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FlightOrderSummaryDto"}},"nextCursor":{"type":"string","example":null,"nullable":true,"description":"Pass as `cursor` to get the next page. `null` means this was the last one. The value is opaque — read it, do not build it."}},"required":["items","nextCursor"]},"FlightCancellationQuoteDto":{"type":"object","properties":{"penaltyCents":{"type":"number","example":2500,"description":"The airline penalty. Stays with us; it is the difference between what you paid and what comes back."},"refundCents":{"type":"number","example":19260,"description":"What is credited to your account if you cancel. Your NET figure — the consumer markup was never in your price and is not in your refund."},"currency":{"type":"string","example":"USD"},"freeCancellation":{"type":"boolean","example":false,"description":"True when the whole amount comes back."},"cancellable":{"type":"boolean","example":true,"description":"False when the airline will not take this order back at all — then cancelling is refused rather than credited at zero."}},"required":["penaltyCents","refundCents","currency","freeCancellation","cancellable"]},"FlightCancellationDto":{"type":"object","properties":{"orderId":{"type":"string","example":"ord_5a11","nullable":true},"status":{"type":"string","example":"CANCELLED"},"refundedCents":{"type":"number","example":19260,"description":"What was credited. 0 on a non-refundable fare."},"currency":{"type":"string","example":"USD"},"refundCredited":{"type":"boolean","example":true,"description":"Whether the credit reached your account. FALSE means the flight IS cancelled and we owe you — we can see it and so can you; do not treat it as \"nothing happened\"."},"message":{"type":"string","nullable":true,"description":"Present only when `refundCredited` is false."}},"required":["orderId","status","refundedCents","currency","refundCredited","message"]},"FlightChangeOptionsRequestDto":{"type":"object","properties":{"removeSliceId":{"type":"string","example":"sbx_sli_hT2mQ1xR9vL4aZ0c","description":"The slice of the existing order you want to replace. Read it from `slices[].id` on the order: `GET /v1/flights/orders/{id}` answers with `FlightSliceDto`, and its `id` is exactly this value. Until 17.09.2026 no response carried one and this parameter could only be guessed at — if you wrote your integration against that, the id is now readable and the guess is no longer needed. It can still be null when the supplier gave the slice no id of its own; such a slice cannot be named here."},"add":{"type":"object","description":"The replacement leg: `{origin, destination, departureDate}`, same vocabulary as a search.","example":{"origin":"BER","destination":"LIS","departureDate":"2026-10-04"}}},"required":["removeSliceId","add"]},"FlightChangeOptionDto":{"type":"object","properties":{"changeId":{"type":"string","example":"chg_9f2c…","description":"Pass this to the change endpoint. Nothing else identifies it."},"differenceCents":{"type":"number","example":4200,"description":"SIGNED. Positive means you pay the difference; NEGATIVE means the new itinerary is cheaper and the difference is credited to your account. There is no separate direction field — read the sign."},"currency":{"type":"string","example":"USD"},"newTotalCents":{"type":"number","example":46200,"nullable":true},"expiresAt":{"type":"string","nullable":true,"example":"2026-10-01T12:34:56.000Z","description":"When this `changeId` stops being bookable, ISO-8601 in UTC — the airline's own deadline, passed through. `null` means the airline gave us no deadline: treat the option as short-lived, re-fetch the options if more than a few minutes pass, and be ready for `410 offer_expired` on `POST …/change`. It is not the only limit either way — a `changeId` is also one of our handles and expires about twenty minutes after this call, so the earlier of the two wins. In the sandbox it is ALWAYS null."},"slices":{"type":"array","items":{"$ref":"#/components/schemas/FlightSliceDto"}}},"required":["changeId","differenceCents","currency","newTotalCents","expiresAt","slices"]},"FlightChangeOptionsDto":{"type":"object","properties":{"orderId":{"type":"string","example":"ord_5a11"},"options":{"type":"array","items":{"$ref":"#/components/schemas/FlightChangeOptionDto"}}},"required":["orderId","options"]},"ConfirmFlightChangeDto":{"type":"object","properties":{"changeId":{"type":"string","example":"chg_9f2c…"}},"required":["changeId"]},"FlightChangeDto":{"type":"object","properties":{"orderId":{"type":"string","example":"ord_5a11"},"status":{"type":"string","example":"CHANGED"},"differenceCents":{"type":"number","example":4200,"description":"Signed, as in the option you took."},"currency":{"type":"string","example":"USD"},"settled":{"type":"boolean","example":true,"description":"Whether the money moved. FALSE means the TICKET IS REISSUED and the difference has not settled — a debt in one direction or the other, never a reason to retry."},"message":{"type":"string","nullable":true}},"required":["orderId","status","differenceCents","currency","settled","message"]},"TransferPlaceDto":{"type":"object","properties":{"type":{"type":"string","enum":["IATA","ATLAS","GPS"],"description":"How `code` should be read. IATA is an airport code, ATLAS an accommodation identifier, GPS a `lat,lng` pair."},"code":{"type":"string","example":"LIS","description":"The identifier itself."},"description":{"type":"string","example":"Hotel Riu Palace, Palma","description":"What is at `code`. Required when `type` is GPS — coordinates alone do not tell the driver where they are going — and ignored otherwise."}},"required":["type","code"]},"SearchTransfersDto":{"type":"object","properties":{"from":{"$ref":"#/components/schemas/TransferPlaceDto"},"to":{"$ref":"#/components/schemas/TransferPlaceDto"},"outbound":{"type":"string","example":"2026-11-02T08:30:00","description":"Local pickup time at the origin, without a timezone suffix. A transfer is booked in the time the driver reads off the clock."},"inbound":{"type":"string","description":"Return leg. Present = round trip, absent = one way."},"adults":{"type":"number","minimum":1,"maximum":9},"children":{"type":"number","minimum":0,"maximum":9,"default":0},"infants":{"type":"number","minimum":0,"maximum":9,"default":0},"language":{"type":"string","example":"en","description":"ISO-639-1 language."}},"required":["from","to","outbound","adults"]},"TransferOfferDto":{"type":"object","properties":{"quoteId":{"type":"string","example":"qte_9dJ2…","description":"Book with this. Valid ~20 minutes, then 410 offer_expired."},"direction":{"type":"string","nullable":true,"example":"ARRIVAL"},"transferType":{"type":"string","nullable":true,"example":"PRIVATE"},"vehicle":{"type":"string","nullable":true,"example":"Car"},"category":{"type":"string","nullable":true,"example":"Standard"},"priceCents":{"type":"number","nullable":true,"example":4200,"description":"Your PURCHASE price."},"currency":{"type":"string","example":"USD"},"minPax":{"type":"number","nullable":true,"example":1},"maxPax":{"type":"number","nullable":true,"example":3},"luggage":{"type":"string","nullable":true,"example":"2"},"journeyMinutes":{"type":"string","nullable":true,"example":"35"},"pickup":{"type":"object","nullable":true,"description":"Meeting point and whether the pickup time must be reconfirmed."},"from":{"type":"object","nullable":true},"to":{"type":"object","nullable":true},"cancellationPolicies":{"type":"array","items":{"type":"object"},"description":"VERBATIM from the supplier. Not summarised into a boolean — a cancellation policy is a legal consequence, and \"free until 18:00 the day before\" does not survive being turned into `refundable: true`. Each entry is `{ amountCents, from }`: `amountCents` is what cancelling costs once that window has started, in the currency of this offer, and `from` is when it starts. NOTE THE TWO DIFFERENCES from a hotel rate: the field is `amountCents`, NOT `chargeCents`, and there is no `until` and no `refundable` flag — free cancellation is simply \"no window has started yet\", and `GET …/orders/{orderId}/cancellation-quote` is the authoritative figure once an order exists. `from` is a local date-time at the pickup point with NO offset (`2026-11-01T08:30:00`), exactly like the hotel windows, so do not parse it as UTC. An empty array means the supplier sent no policy, not that cancelling is free.","example":[{"amountCents":7350,"from":"2026-11-01T08:30:00"}]}},"required":["quoteId","direction","transferType","vehicle","category","priceCents","currency","minPax","maxPax","luggage","journeyMinutes","pickup","from","to","cancellationPolicies"]},"TransferSearchResultDto":{"type":"object","properties":{"offers":{"type":"array","items":{"$ref":"#/components/schemas/TransferOfferDto"}}},"required":["offers"]},"TransferHolderDto":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string","example":"+351912345678","description":"E.164. The driver calls this number when the pickup goes wrong."}},"required":["firstName","lastName","email","phone"]},"CreateTransferOrderDto":{"type":"object","properties":{"quoteId":{"type":"string","example":"qte_9dJ2…","description":"From a search result. Valid for about 20 minutes; after that the answer is 410 offer_expired and you search again."},"externalReference":{"type":"string","description":"YOUR reference for this order, and the idempotency key. Repeating a request with the same value returns the same order instead of buying a second transfer — which is what makes a retry after a timeout safe."},"holder":{"$ref":"#/components/schemas/TransferHolderDto"},"remark":{"type":"string","description":"Free text for the driver, e.g. \"two large suitcases, child seat needed\"."},"language":{"type":"string","example":"en"},"settlement":{"type":"string","enum":["partner","vacabee"],"description":"Optional. Who takes the traveller’s money for this order. The mode follows your API KEY — sending it here is a check, not a choice: a value that contradicts your key is refused rather than obeyed."},"flightNumber":{"type":"string","example":"IB3100","description":"The traveller flight this transfer meets. Required by the supplier when either end is an airport (IATA), so the driver can follow the arrival. Max 7 characters."}},"required":["quoteId","externalReference","holder"]},"TransferSettlementDto":{"type":"object","properties":{"funds":{"type":"string","enum":["captured","released","still_held"],"description":"What happened to the money on your account. `captured` and `released` are final. `still_held` means the supplier gave no verdict yet and our reconciliation worker is finishing the job — do NOT invoice your customer on that state; poll the order until it settles."}},"required":["funds"]},"TransferOrderDto":{"type":"object","properties":{"id":{"type":"string","nullable":true},"externalReference":{"type":"string","example":"my-order-4711","nullable":true,"description":"The externalReference you sent when creating this booking."},"status":{"type":"string","nullable":true,"example":"CONFIRMED"},"reference":{"type":"string","nullable":true,"description":"The supplier's reference."},"amountCents":{"type":"number","nullable":true,"example":4200},"currency":{"type":"string","example":"USD"},"voucherUrl":{"type":"string","nullable":true,"description":"Printable voucher — show it to the traveller."},"holder":{"type":"object","description":"The lead passenger."},"legs":{"type":"array","items":{"type":"object"}},"cancelledAt":{"type":"string","nullable":true},"refundCents":{"type":"number","nullable":true,"description":"Credited back on cancellation."},"settlement":{"$ref":"#/components/schemas/TransferSettlementDto"}},"required":["id","externalReference","status","reference","amountCents","currency","voucherUrl","holder","legs","cancelledAt","refundCents","settlement"]},"TransferOrderPageDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TransferOrderDto"}},"nextCursor":{"type":"string","example":null,"nullable":true,"description":"Pass as `cursor` to get the next page. `null` means this was the last one. The value is opaque — read it, do not build it."}},"required":["items","nextCursor"]},"TransferCancellationQuoteDto":{"type":"object","properties":{"penaltyCents":{"type":"number","example":1050,"description":"Stays with us."},"refundCents":{"type":"number","example":3150,"description":"Credited back to your account."},"currency":{"type":"string","example":"USD"},"freeCancellation":{"type":"boolean","example":false}},"required":["penaltyCents","refundCents","currency","freeCancellation"]},"WebhookEventDto":{"type":"object","properties":{"id":{"type":"string","example":"evt_bk_01J8…","description":"Stable across ALL retries of the same delivery. The key for deduplication: delivery is at-least-once, not exactly-once."},"type":{"type":"string","enum":["booking.confirmed","booking.failed","booking.cancelled","booking.modified","checkout.created","checkout.expired","payment.succeeded","payment.failed","payment.refunded","esim.provisioned","esim.usage_threshold","ledger.low_balance","search_quota.threshold","settlement.invoice_issued","settlement.payment_failed","apikey.revoked"],"example":"booking.confirmed","description":"A receiver should acknowledge an unknown type with 2xx rather than fail — otherwise a new event can knock over an existing receiver."},"createdAt":{"type":"string","example":"2026-09-05T10:00:00.000Z"},"data":{"description":"The payload. Shape depends on `type`.","oneOf":[{"$ref":"#/components/schemas/WebhookBookingDataDto"},{"$ref":"#/components/schemas/WebhookEsimDataDto"},{"$ref":"#/components/schemas/WebhookCheckoutDataDto"}]}},"required":["id","type","createdAt","data"]},"WebhookBookingDataDto":{"type":"object","properties":{"bookingType":{"type":"string","enum":["hotel","flight","transfer","esim"]},"bookingReference":{"type":"string","example":"ABC123"},"status":{"type":"string","example":"CONFIRMED"},"currency":{"type":"string","example":"USD"},"totalAmountCents":{"type":"number","example":48900,"description":"What the guest paid, in the smallest unit — not our purchase price."},"checkInDate":{"type":"string","example":"2026-11-02"},"checkOutDate":{"type":"string","example":"2026-11-06"},"departureDate":{"type":"string","example":"2026-11-02T08:15:00Z"},"returnDate":{"type":"string"},"hotelName":{"type":"string","example":"Hotel Adlon"},"origin":{"type":"string","example":"BER"},"destination":{"type":"string","example":"LIS"},"passengerCount":{"type":"number","example":2},"guestCount":{"type":"number","example":2},"refunded":{"type":"boolean","description":"Only on `booking.cancelled`: whether money goes back. A cancellation without a refund (non-refundable rate) leaves the margin standing."},"reason":{"type":"string","enum":["checkout_expired","checkout_failed"],"example":"checkout_expired","description":"Only on `booking.failed`: a machine-readable cause, so you can branch without parsing prose. `checkout_expired` means nobody paid the hosted checkout in time — nothing was reserved and nothing has to be undone; quote again if the traveller still wants it. Treat an unknown value the way you treat an unknown event type: as \"it failed\", not as an error of your own."}},"required":["bookingType","bookingReference"]},"WebhookEsimDataDto":{"type":"object","properties":{"purchaseId":{"type":"string","example":"pur_01J8…"},"iccid":{"type":"string","nullable":true,"example":"8931…"},"planName":{"type":"string","nullable":true,"example":"Europe 10 GB / 30 days"},"status":{"type":"string","example":"PROVISIONED"}},"required":["purchaseId"]},"WebhookCheckoutDataDto":{"type":"object","properties":{"bookingType":{"type":"string","enum":["hotel","flight","transfer","esim"],"description":"Which vertical the checkout belongs to."},"bookingReference":{"type":"string","example":"ORD-8817","description":"YOUR `externalReference` for this booking — the same string you sent, so this needs no lookup table on your side."},"amountCents":{"type":"number","example":48900,"description":"What the traveller is asked to pay, in the smallest unit."},"currency":{"type":"string","example":"USD"},"expiresAt":{"type":"string","example":"2026-09-05T10:15:00.000Z","description":"On `checkout.created`: when the link stops being payable. On `checkout.expired`: when it did."}},"required":["bookingType","bookingReference","amountCents","currency","expiresAt"]},"WebhookDeliveryHeadersDto":{"type":"object","properties":{"X-Vacabee-Signature":{"type":"string","example":"t=1788570420,v1=8f2c…","description":"HMAC-SHA256 over `{t}.{raw body}`, hex. Compare in constant time and check the age (default 300 s). Verify over the RAW body — parsing and re-serialising yields a different string and therefore a different signature. Recomputed on every attempt, because otherwise every retry would fail your time window."},"X-Vacabee-Event":{"type":"string","example":"booking.confirmed"},"X-Vacabee-Delivery":{"type":"string","example":"dl_01J8…","description":"The delivery. The same across all attempts."},"X-Vacabee-Attempt":{"type":"string","example":"1","description":"Which attempt this is, from 1."},"X-Vacabee-Timestamp":{"type":"string","example":"1788570420"}},"required":["X-Vacabee-Signature","X-Vacabee-Event","X-Vacabee-Delivery","X-Vacabee-Attempt","X-Vacabee-Timestamp"]}}}}