{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/authentication/api-keys"
}
}
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "QUOTE_EXPIRED",
"message": "The quote behind this checkout expired at 2026-09-04T12:39:56Z.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"expires_at": "2026-09-04T12:39:56Z",
"quote_id": "2097152",
"reason": "travelers_changed"
}
{
"error": {
"code": "BAD_REQUEST",
"message": "A required field is missing or invalid.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "The request was declined for this offer. Try another offer.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "The request timed out before a result was available. Retry the request.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
Trip & Payment
agent-payment submit
Submit SPT payments; card submissions must use the payment hostname and are refused here
POST
/
v1
/
agent_payment
/
submit
Submit SPT payments; card submissions must use the payment hostname and are refused here
{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/authentication/api-keys"
}
}
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "QUOTE_EXPIRED",
"message": "The quote behind this checkout expired at 2026-09-04T12:39:56Z.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"expires_at": "2026-09-04T12:39:56Z",
"quote_id": "2097152",
"reason": "travelers_changed"
}
{
"error": {
"code": "BAD_REQUEST",
"message": "A required field is missing or invalid.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "The request was declined for this offer. Try another offer.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "The request timed out before a result was available. Retry the request.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}
Typed submissions require a jnk_ API key via X-API-Key (ApiKeyAuth) or Authorization: Bearer (BearerAuth), a tenant-bound booking scope, quote_id and Idempotency-Key, and return a PaymentAttemptOutcome (200 known outcome / 202 pending). OAuth/JWT bearer tokens are supported only for the legacy flat token body, which keeps its existing authorization response. Request bodies are limited to 16 KiB. Card submissions must be sent to the payment hostname (POST https://pay.<env-domain>/v1/agent_payment/submit); see the partner card payments guide. This route refuses card submissions with 400 CREDENTIAL_FORMAT_INVALID.
Required on a typed submission (a body with payment); without it the request is refused with 400 CREDENTIAL_FORMAT_INVALID. Ignored on the legacy body. 1–255 printable ASCII characters. Reuse only for the same payment submission: the same key with the same body replays the first outcome, with a different body it is refused.
The quote the traveler approved: the quote_id checkout returned. The payment is taken against this quote only; a quote that is no longer payable is refused with 410 QUOTE_EXPIRED and nothing is charged.
The trip this attempt pays, written with a trip_ prefix (trip_1048576); the trip answers carry the same id without it (1048576). Strip the prefix to compare the two.
Why the payment has not gone through, or null. On the checkout_url payment page, a card the issuer declines (card_declined) or whose authentication fails (authentication_failed) is reported here while payment_status stays pending and recovery.action is poll: the payer can use another card on the same page until this payment's quote_expires_at. It returns to null when a card is authorized. CARD_ALIAS_EXPIRED: The submitted card details can no longer be used for this payment. Follow recovery.action; when it is retry_new_key: Submit the card again on the pay hostname with a new Idempotency-Key.
Why the booking failed, when it failed after payment and the cause is known: offer_unavailable, price_changed, booking_not_created (the supplier holds no booking; nothing was booked and no money was taken), booking_cancelled_at_provider, ticketing_refused. Null otherwise. For offer_unavailable, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The booking.failed webhook carries the same reason with a sentence to show the traveller (failure_message).
Deadline for completing this payment (RFC 3339). It is the quote deadline the checkout response and the trip's quote call expires_at, unless they say payment_stays_open: then this payment has its own, later deadline.
Where the customer authenticates when recovery.action is authenticate: open url before expires_at. For a Shared Payment Token (spt), url is a Jinko-hosted page that needs the token's hashed value: read the issued token's next_action.use_stripe_sdk.value with your own Stripe secret key and open url + "#hv=" + <value>, passing the value unchanged. The value travels in the URL fragment, which keeps it out of server logs.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Jinko Platform","description":"Connect your AI agent to flights, hotels, car rentals, and bookings through MCP, REST API, TypeScript SDK, or CLI.","colors":{"primary":"#FF6363","light":"#FF807C","dark":"#BA4B4A"},"logo":{"light":"https://mintcdn.com/jinko-dev/k6P2DyAYQF0FPJQi/logo/jinko-logo.png?fit=max\u0026auto=format\u0026n=k6P2DyAYQF0FPJQi\u0026q=85\u0026s=785a20dc553a2698bfffad325d1198d0","dark":"https://mintcdn.com/jinko-dev/k6P2DyAYQF0FPJQi/logo/jinko-logo.png?fit=max\u0026auto=format\u0026n=k6P2DyAYQF0FPJQi\u0026q=85\u0026s=785a20dc553a2698bfffad325d1198d0"},"favicon":"https://mintcdn.com/jinko-dev/k6P2DyAYQF0FPJQi/favicon.png?fit=max\u0026auto=format\u0026n=k6P2DyAYQF0FPJQi\u0026q=85\u0026s=770e72a193924011a067dcacdcb654cf","navbar":{"links":[{"href":"https://dashboard.gojinko.com","label":"Dashboard"}],"primary":{"type":"button","label":"Get API Key","href":"https://dashboard.gojinko.com/developers/keys"}},"footer":{"socials":{"website":"https://gojinko.com"}},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"jinko-dev","hasAudioNarration":false,"actualSubdomain":"jinko-dev","customDomains":["docs.dev.gojinko.com"],"gitSource":{"type":"github","owner":"jinkoso","repo":"jinko-dev-platform","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":""},"entitlements":{},"buildId":"6aeece39c11f500273ffd5ec","clientVersion":"0.0.4076","searchFilterCounts":[{"language":"default","tag":"API reference","count":63},{"language":"default","tag":"CLI","count":49},{"language":"default","tag":"Flights","count":43},{"language":"default","tag":"Documentation","count":42},{"language":"default","tag":"MCP","count":23},{"language":"default","tag":"Manage","count":20},{"language":"default","tag":"Trip \u0026 Payment","count":19},{"language":"default","tag":"Discovery","count":17},{"language":"default","tag":"Hotels","count":16},{"language":"default","tag":"Travel Demand","count":14}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api/agent-payment/submit","slug":"/api/agent-payment/submit","pageMetadata":{"title":"agent-payment submit","sidebarTitle":"/v1/agent_payment/submit","description":"Submit SPT payments; card submissions must use the payment hostname and are refused here","openapi":"api-reference/public-api.yaml POST /v1/agent_payment/submit","href":"/api/agent-payment/submit"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Submit SPT payments; card submissions must use the payment hostname and are refused here\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={code:`code`,p:`p`,..._provideComponents(),...props.components};return _jsxs(_components.p,{children:[`Typed submissions require a jnk_ API key via X-API-Key (ApiKeyAuth) or Authorization: Bearer (BearerAuth), a tenant-bound booking scope, quote_id and Idempotency-Key, and return a PaymentAttemptOutcome (200 known outcome / 202 pending). OAuth/JWT bearer tokens are supported only for the legacy flat token body, which keeps its existing authorization response. Request bodies are limited to 16 KiB. Card submissions must be sent to the payment hostname (`,_jsx(_components.code,{children:`POST https://pay.\u003cenv-domain>/v1/agent_payment/submit`}),`); see the partner card payments guide. This route refuses card submissions with 400 CREDENTIAL_FORMAT_INVALID.`]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"agent-payment submit","sidebarTitle":"/v1/agent_payment/submit","description":"Submit SPT payments; card submissions must use the payment hostname and are refused here","openapi":"api-reference/public-api.yaml POST /v1/agent_payment/submit","href":"/api/agent-payment/submit"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"tags":["Pricing \u0026 booking"],"summary":"Submit SPT payments; card submissions must use the payment hostname and are refused here","description":"Submit SPT payments; card submissions must use the payment hostname and are refused here","security":["39839d48-3c13-4f4e-a6d4-c19a28337289","ca28de3f-4159-4a27-b812-7e0c55dfec51"],"parameters":["fd7d1f39-0452-4925-83c6-9877484f8dac"],"requestBody":"31ab54b2-dd76-4dd8-b97d-ca71454bfb99","responses":{"200":"0ea5566b-0ab2-4e0f-a895-f6ee1f4e8985","202":"8f10a170-7fec-4911-a283-af6b893a0f0a","400":"6ff2a077-a26b-453f-bb61-b77c67ac3f63","401":"76314fbb-599b-4e49-ab8a-d7ae403c10d7","402":"17efde8e-705b-467f-a0d6-8e23524710e2","403":"9342ff50-3565-49a9-8fac-01198770f8f3","404":"3afc3ae4-236c-4eb6-8e4c-524fbc8c66dd","409":"100197e3-c733-4285-a24a-ca818bcd4831","410":"673229f8-d2f8-4ed2-baf4-ccdffefab3e3","422":"6d587ee1-4e2b-4a79-90de-2f9978104855","429":"c10d3c41-f8b3-4b06-9e13-ec43cfff4056","502":"88fd1f6b-06f6-4f19-9358-ddfd4503be9c","503":"ab4836d2-af98-475f-bbb6-ec7e10c210d6","504":"40dae6f5-63fb-4cdf-8843-3eaca733a48e"},"method":"post","type":"path","servers":["6c2e2c14-8667-4ef1-a6c7-d1e7fb982378","0b2c8592-7b6b-4acc-9351-2a69f3e0f42a"],"path":"/v1/agent_payment/submit","baseUrlOptions":["https://api.gojinko.com","https://api.sandbox.gojinko.com"],"title":"Submit SPT payments; card submissions must use the payment hostname and are refused here","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"fd7d1f39-0452-4925-83c6-9877484f8dac":{"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[ -~]+$(?![\\s\\S])","description":"Required on a typed submission (a body with `payment`); without it the request is refused with 400 `CREDENTIAL_FORMAT_INVALID`. Ignored on the legacy body. 1–255 printable ASCII characters. Reuse only for the same payment submission: the same key with the same body replays the first outcome, with a different body it is refused.","isRequired":false,"uniqueKey":"","typeLabel":"string"},"required":false,"name":"Idempotency-Key","in":"header"}},"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["trip_id","quote_id","payment"],"properties":{"trip_id":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.trip_id","typeLabel":"string"},"quote_id":{"type":"string","pattern":"^[1-9][0-9]{0,17}$(?![\\s\\S])","description":"The quote the traveler approved: the `quote_id` checkout returned. The payment is taken against this quote only; a quote that is no longer payable is refused with 410 `QUOTE_EXPIRED` and nothing is charged.","example":"2097152","isRequired":true,"uniqueKey":"oneOf.0.quote_id","typeLabel":"string"},"payment":{"type":"object","required":["type","shared_payment_token"],"properties":{"type":{"type":"string","enum":["spt"],"isRequired":true,"uniqueKey":"oneOf.0.payment.type","typeLabel":"enum\u003cstring>"},"shared_payment_token":{"type":"string","minLength":1,"isRequired":true,"uniqueKey":"oneOf.0.payment.shared_payment_token","typeLabel":"string"}},"additionalProperties":false,"isRequired":true,"uniqueKey":"oneOf.0.payment","typeLabel":"object"}},"additionalProperties":false,"uniqueKey":"oneOf.0","typeLabel":"object"},{"type":"object","required":["trip_id","shared_payment_token"],"properties":{"trip_id":{"type":"string","example":"trip_1048576","isRequired":true,"uniqueKey":"oneOf.1.trip_id","typeLabel":"string"},"shared_payment_token":{"type":"string","example":"spt_1Nq8L2eZvKYlo2C0","isRequired":true,"uniqueKey":"oneOf.1.shared_payment_token","typeLabel":"string"}},"uniqueKey":"oneOf.1","typeLabel":"object"}],"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"trip_id":"\u003cstring>","quote_id":"2097152","payment":{"type":"spt","shared_payment_token":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"0ea5566b-0ab2-4e0f-a895-f6ee1f4e8985":{"description":"Legacy authorization result or typed payment outcome","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["payment_attempt_id","trip_id","quote_id","quoted_cart_id","payment_status","booking_status","payment_error","recovery","recovery_status"],"properties":{"payment_attempt_id":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.payment_attempt_id","typeLabel":"string"},"trip_id":{"type":"string","description":"The trip this attempt pays, written with a `trip_` prefix (`trip_1048576`); the trip answers carry the same id without it (`1048576`). Strip the prefix to compare the two.","example":"trip_1048576","isRequired":true,"uniqueKey":"oneOf.0.trip_id","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote this payment is taken against.","example":"2097152","isRequired":true,"uniqueKey":"oneOf.0.quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"integer","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","deprecated":true,"isRequired":true,"uniqueKey":"oneOf.0.quoted_cart_id","typeLabel":"integer"},"payment_status":{"type":"string","enum":["pending","requires_authentication","authorized","captured","declined","cancelling","cancelled","expired","failed"],"isRequired":true,"uniqueKey":"oneOf.0.payment_status","typeLabel":"enum\u003cstring>"},"booking_status":{"type":"string","description":"The detailed status of the booking this payment started, `not_scheduled` until booking begins. `booking_state` on GET /v1/trip/{trip_id} is its summary.","isRequired":true,"uniqueKey":"oneOf.0.booking_status","typeLabel":"string"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"oneOf.0.payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"description":"Why the payment has not gone through, or null. On the `checkout_url` payment page, a card the issuer declines (`card_declined`) or whose authentication fails (`authentication_failed`) is reported here while `payment_status` stays `pending` and `recovery.action` is `poll`: the payer can use another card on the same page until this payment's `quote_expires_at`. It returns to null when a card is authorized. `CARD_ALIAS_EXPIRED`: The submitted card details can no longer be used for this payment. Follow `recovery.action`; when it is `retry_new_key`: Submit the card again on the pay hostname with a new Idempotency-Key.","isRequired":true,"uniqueKey":"oneOf.0.payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"description":"Why the payment has not gone through, or null. On the `checkout_url` payment page, a card the issuer declines (`card_declined`) or whose authentication fails (`authentication_failed`) is reported here while `payment_status` stays `pending` and `recovery.action` is `poll`: the payer can use another card on the same page until this payment's `quote_expires_at`. It returns to null when a card is authorized. `CARD_ALIAS_EXPIRED`: The submitted card details can no longer be used for this payment. Follow `recovery.action`; when it is `retry_new_key`: Submit the card again on the pay hostname with a new Idempotency-Key.","isRequired":true,"uniqueKey":"oneOf.0.payment_error.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"oneOf.0.payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"oneOf.0.recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"oneOf.0.recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"isRequired":true,"uniqueKey":"oneOf.0.recovery","typeLabel":"object"},"recovery_status":{"type":"string","enum":["automatic","manual_review"],"isRequired":true,"uniqueKey":"oneOf.0.recovery_status","typeLabel":"enum\u003cstring>"},"fulfillment_cart_id":{"type":"integer","description":"Deprecated: use `booking_ref` instead. An internal number for the booking this payment funds.","deprecated":true,"uniqueKey":"oneOf.0.fulfillment_cart_id","typeLabel":"integer"},"failure_reason":{"oneOf":[{"type":"string","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"oneOf.0.failure_reason.oneOf.0","typeLabel":"string"},{"type":"null","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"oneOf.0.failure_reason.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.failure_reason","typeLabel":"string | null"},"items":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"integer","description":"Deprecated: use `booked_item_id` instead. The booked item as an integer.","deprecated":true,"isRequired":true,"uniqueKey":"oneOf.0.\\items.items.[INDEX].item_id","typeLabel":"integer"},"outcome":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.\\items.items.[INDEX].outcome","typeLabel":"string"},"booked_item_id":{"type":"string","description":"The booked item, as get_booking and the servicing routes name it. Absent only when the item cannot be named yet.","example":"itm_aaaaaaaaaaaaafhuxsdxpbzrbfz5hm3a","uniqueKey":"oneOf.0.\\items.items.[INDEX].booked_item_id","typeLabel":"string"},"failure_reason":{"oneOf":[{"type":"string","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"oneOf.0.\\items.items.[INDEX].failure_reason.oneOf.0","typeLabel":"string"},{"type":"null","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"oneOf.0.\\items.items.[INDEX].failure_reason.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.0.\\items.items.[INDEX].failure_reason","typeLabel":"string | null"}},"required":["item_id","outcome"],"uniqueKey":"oneOf.0.\\items.items.[INDEX]","typeLabel":"object"},"uniqueKey":"oneOf.0.\\items","typeLabel":"object[]"},"booking_ref":{"type":"string","description":"The booking reference. Absent until the booking has one; never null.","uniqueKey":"oneOf.0.booking_ref","typeLabel":"string"},"quote_expires_at":{"type":"string","format":"date-time","description":"Deadline for completing this payment (RFC 3339). It is the quote deadline the checkout response and the trip's `quote` call `expires_at`, unless they say `payment_stays_open`: then this payment has its own, later deadline.","uniqueKey":"oneOf.0.quote_expires_at","typeLabel":"string\u003cdate-time>"},"retry_after_seconds":{"type":"integer","description":"Seconds to wait before reading the payment attempt again. Present only while `recovery.action` is `poll`; absent otherwise, never null.","uniqueKey":"oneOf.0.retry_after_seconds","typeLabel":"integer"},"authentication":{"type":"object","properties":{"url":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.authentication.url","typeLabel":"string"},"expires_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"oneOf.0.authentication.expires_at","typeLabel":"string\u003cdate-time>"}},"required":["url","expires_at"],"description":"Where the customer authenticates when `recovery.action` is `authenticate`: open `url` before `expires_at`. For a Shared Payment Token (`spt`), `url` is a Jinko-hosted page that needs the token's hashed value: read the issued token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and open `url + \"#hv=\" + \u003cvalue>`, passing the value unchanged. The value travels in the URL fragment, which keeps it out of server logs.","uniqueKey":"oneOf.0.authentication","typeLabel":"object"},"money":{"type":"object","properties":{"authorized":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"oneOf.0.money.authorized.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"oneOf.0.money.authorized.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"oneOf.0.money.authorized.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"oneOf.0.money.authorized.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"oneOf.0.money.authorized.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"oneOf.0.money.authorized","typeLabel":"object"},"captured":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"oneOf.0.money.captured.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"oneOf.0.money.captured.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"oneOf.0.money.captured.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"oneOf.0.money.captured.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"oneOf.0.money.captured.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"oneOf.0.money.captured","typeLabel":"object"},"released":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"oneOf.0.money.released.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"oneOf.0.money.released.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"oneOf.0.money.released.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"oneOf.0.money.released.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"oneOf.0.money.released.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"oneOf.0.money.released","typeLabel":"object"},"refunded":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"oneOf.0.money.refunded.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"oneOf.0.money.refunded.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"oneOf.0.money.refunded.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"oneOf.0.money.refunded.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"oneOf.0.money.refunded.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"oneOf.0.money.refunded","typeLabel":"object"},"externally_reimbursed":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"oneOf.0.money.externally_reimbursed.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"oneOf.0.money.externally_reimbursed.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"oneOf.0.money.externally_reimbursed.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"oneOf.0.money.externally_reimbursed.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"oneOf.0.money.externally_reimbursed.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"oneOf.0.money.externally_reimbursed","typeLabel":"object"},"resolution_status":{"type":"string","enum":["pending","resolved","manual_review","external_reimbursement_pending","externally_reimbursed"],"uniqueKey":"oneOf.0.money.resolution_status","typeLabel":"enum\u003cstring>"},"refund_reference":{"type":"string","uniqueKey":"oneOf.0.money.refund_reference","typeLabel":"string"}},"uniqueKey":"oneOf.0.money","typeLabel":"object"}},"uniqueKey":"oneOf.0","typeLabel":"object"},{"type":"object","properties":{"quote_id":{"type":"string","description":"The quote this payment was taken against. This submission names no quote, so it pays the trip’s latest payable quote; compare this with the `quote_id` the traveler approved.","example":"2097152","uniqueKey":"oneOf.1.quote_id","typeLabel":"string"},"fulfillment_cart_id":{"type":"integer","description":"Deprecated: use `booking_ref` instead. An internal number for the booking.","deprecated":true,"uniqueKey":"oneOf.1.fulfillment_cart_id","typeLabel":"integer"},"status":{"type":"string","example":"processing","uniqueKey":"oneOf.1.status","typeLabel":"string"},"payment_verified":{"type":"boolean","uniqueKey":"oneOf.1.payment_verified","typeLabel":"boolean"},"message":{"type":"string","uniqueKey":"oneOf.1.message","typeLabel":"string"},"booking_ref":{"type":"string","description":"The Jinko booking reference for the trip just paid — hand it to `POST /v1/get_booking` (`booking_ref`) to retrieve or service the booking. Present when the token was authorized (and when the trip was already past payment); absent when the payment could not be authorized and `checkout_url` is returned instead. When `payment_status` is `requires_authentication` it can be present before payment completes: read `payment_status`, not this field, to tell whether the payment went through.","example":"JNK-XEVGW5","uniqueKey":"oneOf.1.booking_ref","typeLabel":"string"},"checkout_url":{"type":"string","description":"Hosted-checkout fallback, present when the payment could not be authorized (for example a card decline). Not returned when `payment_status` is `requires_authentication`.","uniqueKey":"oneOf.1.checkout_url","typeLabel":"string"},"recap_token":{"type":"string","uniqueKey":"oneOf.1.recap_token","typeLabel":"string"},"payment_status":{"type":"string","enum":["pending","requires_authentication","authorized","captured","declined","cancelling","cancelled","expired","failed"],"description":"Status of the payment attempt behind this submission, the same values as `payment_attempt.payment_status`. `requires_authentication`: the card issuer asked for 3-D Secure; `payment_verified` is false and no `checkout_url` is returned. Send the traveler to `authentication.url`, with the Shared Payment Token's hashed value appended as that field describes, to complete it before `quote_expires_at`, then poll `GET /v1/trip/{trip_id}` until `payment_attempt.payment_status` is none of `requires_authentication`, `cancelling` or `pending` (`cancelling` is a transient cleanup state and `pending` is still in progress — keep polling). `authorized` / `captured`: the payment went through. `failed` / `declined` / `cancelled`: it did not — submit again with a new token before `quote_expires_at`. `expired`: it did not, and the quote expired with it — call `POST /v1/checkout` again to price a new quote, then mint and submit a new token.","example":"requires_authentication","uniqueKey":"oneOf.1.payment_status","typeLabel":"enum\u003cstring>"},"quote_expires_at":{"type":"string","format":"date-time","description":"Deadline for completing this payment, including 3-D Secure authentication (RFC 3339). With `payment_stays_open`, this is one hour from when the payment started, or the quote deadline if that is later. Otherwise it is the quote deadline the checkout response and the trip's `quote` call `expires_at`. After it, call `POST /v1/checkout` again for a new quote, then submit a new token.","example":"2026-06-01T12:39:56Z","uniqueKey":"oneOf.1.quote_expires_at","typeLabel":"string\u003cdate-time>"},"authentication":{"type":"object","properties":{"url":{"type":"string","format":"uri","isRequired":true,"uniqueKey":"oneOf.1.authentication.url","typeLabel":"string\u003curi>"},"expires_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"oneOf.1.authentication.expires_at","typeLabel":"string\u003cdate-time>"}},"required":["url","expires_at"],"description":"Jinko-hosted page where the traveler completes 3-D Secure, present when `payment_status` is `requires_authentication`: the same object a card submit and `payment_attempt` carry. Open `url` before `expires_at`, which is `quote_expires_at`. Read the Shared Payment Token you issued from the Stripe API (`GET https://api.stripe.com/v1/shared_payment/issued_tokens/{id}` with your own Stripe secret key, `{id}` being the token you submitted) and append `#hv=` and its `next_action.use_stripe_sdk.value`, unchanged: `authentication.url + \"#hv=\" + next_action.use_stripe_sdk.value`. The value travels in the URL fragment, which keeps it out of server logs. The traveler completes the bank challenge on that page before `quote_expires_at`. To run the challenge on your own page instead, load Stripe.js with your own publishable key and call `stripe.handleNextAction({ hashedValue })` with that value. Then poll `GET /v1/trip/{trip_id}` until `payment_attempt.payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","uniqueKey":"oneOf.1.authentication","typeLabel":"object"},"authentication_url":{"type":"string","format":"uri","description":"Deprecated: use `authentication.url` instead. The same value.","deprecated":true,"uniqueKey":"oneOf.1.authentication_url","typeLabel":"string\u003curi>"}},"uniqueKey":"oneOf.1","typeLabel":"object"}],"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"payment_attempt_id":"\u003cstring>","trip_id":"trip_1048576","quote_id":"2097152","quoted_cart_id":123,"payment_status":"pending","booking_status":"\u003cstring>","payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"recovery_status":"automatic","fulfillment_cart_id":123,"failure_reason":"booking_not_created","items":[{"item_id":123,"outcome":"\u003cstring>","booked_item_id":"itm_aaaaaaaaaaaaafhuxsdxpbzrbfz5hm3a","failure_reason":"booking_not_created"}],"booking_ref":"\u003cstring>","quote_expires_at":"2023-11-07T05:31:56Z","retry_after_seconds":123,"authentication":{"url":"\u003cstring>","expires_at":"2023-11-07T05:31:56Z"},"money":{"authorized":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"captured":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"released":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"refunded":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"externally_reimbursed":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"resolution_status":"pending","refund_reference":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"},"8f10a170-7fec-4911-a283-af6b893a0f0a":{"description":"Payment accepted and pending; poll the attempt after Retry-After.","headers":{"Retry-After":{"schema":{"type":"string"},"description":"Polling delay supplied by the service."}},"content":{"application/json":{"schema":{"type":"object","properties":{"payment_attempt_id":{"type":"string","isRequired":true,"uniqueKey":"payment_attempt_id","typeLabel":"string"},"trip_id":{"type":"string","description":"The trip this attempt pays, written with a `trip_` prefix (`trip_1048576`); the trip answers carry the same id without it (`1048576`). Strip the prefix to compare the two.","example":"trip_1048576","isRequired":true,"uniqueKey":"trip_id","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote this payment is taken against.","example":"2097152","isRequired":true,"uniqueKey":"quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"integer","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","deprecated":true,"isRequired":true,"uniqueKey":"quoted_cart_id","typeLabel":"integer"},"payment_status":{"type":"string","enum":["pending","requires_authentication","authorized","captured","declined","cancelling","cancelled","expired","failed"],"isRequired":true,"uniqueKey":"payment_status","typeLabel":"enum\u003cstring>"},"booking_status":{"type":"string","description":"The detailed status of the booking this payment started, `not_scheduled` until booking begins. `booking_state` on GET /v1/trip/{trip_id} is its summary.","isRequired":true,"uniqueKey":"booking_status","typeLabel":"string"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"description":"Why the payment has not gone through, or null. On the `checkout_url` payment page, a card the issuer declines (`card_declined`) or whose authentication fails (`authentication_failed`) is reported here while `payment_status` stays `pending` and `recovery.action` is `poll`: the payer can use another card on the same page until this payment's `quote_expires_at`. It returns to null when a card is authorized. `CARD_ALIAS_EXPIRED`: The submitted card details can no longer be used for this payment. Follow `recovery.action`; when it is `retry_new_key`: Submit the card again on the pay hostname with a new Idempotency-Key.","isRequired":true,"uniqueKey":"payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"description":"Why the payment has not gone through, or null. On the `checkout_url` payment page, a card the issuer declines (`card_declined`) or whose authentication fails (`authentication_failed`) is reported here while `payment_status` stays `pending` and `recovery.action` is `poll`: the payer can use another card on the same page until this payment's `quote_expires_at`. It returns to null when a card is authorized. `CARD_ALIAS_EXPIRED`: The submitted card details can no longer be used for this payment. Follow `recovery.action`; when it is `retry_new_key`: Submit the card again on the pay hostname with a new Idempotency-Key.","isRequired":true,"uniqueKey":"payment_error.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"isRequired":true,"uniqueKey":"recovery","typeLabel":"object"},"recovery_status":{"type":"string","enum":["automatic","manual_review"],"isRequired":true,"uniqueKey":"recovery_status","typeLabel":"enum\u003cstring>"},"fulfillment_cart_id":{"type":"integer","description":"Deprecated: use `booking_ref` instead. An internal number for the booking this payment funds.","deprecated":true,"uniqueKey":"fulfillment_cart_id","typeLabel":"integer"},"failure_reason":{"oneOf":[{"type":"string","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"failure_reason.oneOf.0","typeLabel":"string"},{"type":"null","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"failure_reason.oneOf.1","typeLabel":"null"}],"uniqueKey":"failure_reason","typeLabel":"string | null"},"items":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"integer","description":"Deprecated: use `booked_item_id` instead. The booked item as an integer.","deprecated":true,"isRequired":true,"uniqueKey":"\\items.items.[INDEX].item_id","typeLabel":"integer"},"outcome":{"type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].outcome","typeLabel":"string"},"booked_item_id":{"type":"string","description":"The booked item, as get_booking and the servicing routes name it. Absent only when the item cannot be named yet.","example":"itm_aaaaaaaaaaaaafhuxsdxpbzrbfz5hm3a","uniqueKey":"\\items.items.[INDEX].booked_item_id","typeLabel":"string"},"failure_reason":{"oneOf":[{"type":"string","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"\\items.items.[INDEX].failure_reason.oneOf.0","typeLabel":"string"},{"type":"null","description":"Why the booking failed, when it failed after payment and the cause is known: `offer_unavailable`, `price_changed`, `booking_not_created` (the supplier holds no booking; nothing was booked and no money was taken), `booking_cancelled_at_provider`, `ticketing_refused`. Null otherwise. For `offer_unavailable`, the supplier no longer sells the priced offer. Nothing was booked and the card authorisation was released. Search again and book a new offer. The `booking.failed` webhook carries the same reason with a sentence to show the traveller (`failure_message`).","example":"booking_not_created","uniqueKey":"\\items.items.[INDEX].failure_reason.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].failure_reason","typeLabel":"string | null"}},"required":["item_id","outcome"],"uniqueKey":"\\items.items.[INDEX]","typeLabel":"object"},"uniqueKey":"\\items","typeLabel":"object[]"},"booking_ref":{"type":"string","description":"The booking reference. Absent until the booking has one; never null.","uniqueKey":"booking_ref","typeLabel":"string"},"quote_expires_at":{"type":"string","format":"date-time","description":"Deadline for completing this payment (RFC 3339). It is the quote deadline the checkout response and the trip's `quote` call `expires_at`, unless they say `payment_stays_open`: then this payment has its own, later deadline.","uniqueKey":"quote_expires_at","typeLabel":"string\u003cdate-time>"},"retry_after_seconds":{"type":"integer","description":"Seconds to wait before reading the payment attempt again. Present only while `recovery.action` is `poll`; absent otherwise, never null.","uniqueKey":"retry_after_seconds","typeLabel":"integer"},"authentication":{"type":"object","properties":{"url":{"type":"string","isRequired":true,"uniqueKey":"authentication.url","typeLabel":"string"},"expires_at":{"type":"string","format":"date-time","isRequired":true,"uniqueKey":"authentication.expires_at","typeLabel":"string\u003cdate-time>"}},"required":["url","expires_at"],"description":"Where the customer authenticates when `recovery.action` is `authenticate`: open `url` before `expires_at`. For a Shared Payment Token (`spt`), `url` is a Jinko-hosted page that needs the token's hashed value: read the issued token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and open `url + \"#hv=\" + \u003cvalue>`, passing the value unchanged. The value travels in the URL fragment, which keeps it out of server logs.","uniqueKey":"authentication","typeLabel":"object"},"money":{"type":"object","properties":{"authorized":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"money.authorized.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"money.authorized.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"money.authorized.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"money.authorized.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"money.authorized.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"money.authorized","typeLabel":"object"},"captured":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"money.captured.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"money.captured.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"money.captured.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"money.captured.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"money.captured.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"money.captured","typeLabel":"object"},"released":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"money.released.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"money.released.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"money.released.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"money.released.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"money.released.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"money.released","typeLabel":"object"},"refunded":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"money.refunded.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"money.refunded.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"money.refunded.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"money.refunded.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"money.refunded.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"money.refunded","typeLabel":"object"},"externally_reimbursed":{"type":"object","properties":{"amount":{"type":"number","description":"Deprecated: use `value` instead (the same integer) where this object carries decimal_places. Where it does not, the figure is in MAJOR units and the field holding this object is itself deprecated: read its `*_money` sibling. The two-scale rule applies only to deprecated fields. Alternative to `value` on some endpoints (the two never appear together); its scale depends on decimal_places. When this object carries decimal_places, amount is an INTEGER in minor units — divide by 10 ** decimal_places (e.g. select_ancillaries total_with_ancillaries). When there is no decimal_places field, amount is a decimal in MAJOR units, safe to display as-is (e.g. trip and checkout totals).","deprecated":true,"uniqueKey":"money.externally_reimbursed.amount","typeLabel":"number"},"value":{"type":"integer","description":"Integer amount in MINOR units, always paired with decimal_places — divide by 10 ** decimal_places to display. Example: value 15977 with decimal_places 2 is 159.77 USD. Rendering this field directly shows prices 100x too high for 2-decimal currencies.","example":41250,"uniqueKey":"money.externally_reimbursed.value","typeLabel":"integer"},"currency":{"type":"string","description":"ISO 4217 currency code.","example":"USD","uniqueKey":"money.externally_reimbursed.currency","typeLabel":"string"},"decimal_places":{"type":"integer","description":"Scale of the integer value/amount: display = integer / 10 ** decimal_places. Always sent alongside minor-unit amounts. Usually the ISO 4217 digits of the currency (2 for USD/EUR/GBP, 0 for JPY/KRW, 3 for BHD/JOD/KWD) but currency-converted prices can carry a different scale — ALWAYS use the decimal_places sent with the amount, never a hardcoded 2. Only if the field is genuinely absent on a value-shaped object, fall back to the ISO digits for the currency.","example":2,"uniqueKey":"money.externally_reimbursed.decimal_places","typeLabel":"integer"},"display":{"type":"string","description":"The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. \"USD 159.77\". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is \"JPY 15615.00\"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.","example":"USD 412.50","uniqueKey":"money.externally_reimbursed.display","typeLabel":"string"}},"description":"A money figure in one of two scales. New integrations read the `*_money` field beside it (a `MoneyValue`) where there is one, and `value` on objects that carry it; the rule below applies only to the deprecated forms. When `decimal_places` is present, `value` (or the deprecated `amount`) is an INTEGER in minor units: divide by 10 ** decimal_places. When it is absent, the deprecated `amount` is already in MAJOR units. Branch on whether decimal_places is present in the response you received, never on the currency code or the field name. `display` is the same figure as a string to show.","uniqueKey":"money.externally_reimbursed","typeLabel":"object"},"resolution_status":{"type":"string","enum":["pending","resolved","manual_review","external_reimbursement_pending","externally_reimbursed"],"uniqueKey":"money.resolution_status","typeLabel":"enum\u003cstring>"},"refund_reference":{"type":"string","uniqueKey":"money.refund_reference","typeLabel":"string"}},"uniqueKey":"money","typeLabel":"object"}},"required":["payment_attempt_id","trip_id","quote_id","quoted_cart_id","payment_status","booking_status","payment_error","recovery","recovery_status"],"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"payment_attempt_id":"\u003cstring>","trip_id":"trip_1048576","quote_id":"2097152","quoted_cart_id":123,"payment_status":"pending","booking_status":"\u003cstring>","payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"recovery_status":"automatic","fulfillment_cart_id":123,"failure_reason":"booking_not_created","items":[{"item_id":123,"outcome":"\u003cstring>","booked_item_id":"itm_aaaaaaaaaaaaafhuxsdxpbzrbfz5hm3a","failure_reason":"booking_not_created"}],"booking_ref":"\u003cstring>","quote_expires_at":"2023-11-07T05:31:56Z","retry_after_seconds":123,"authentication":{"url":"\u003cstring>","expires_at":"2023-11-07T05:31:56Z"},"money":{"authorized":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"captured":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"released":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"refunded":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"externally_reimbursed":{"amount":123,"value":41250,"currency":"USD","decimal_places":2,"display":"USD 412.50"},"resolution_status":"pending","refund_reference":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"},"6ff2a077-a26b-453f-bb61-b77c67ac3f63":{"description":"Payment credential format or validity refusal. **`CREDENTIAL_FORMAT_INVALID`** — The typed payment body or Idempotency-Key has an invalid format. Correct the named field and resubmit with a valid Idempotency-Key. **`PAYMENT_CREDENTIAL_INVALID`** — The payment credential is invalid. Follow recovery.action and supply a replacement credential when required. **`BAD_REQUEST`** — The request was malformed or failed validation. Fix the request as the message describes; retrying it unchanged cannot succeed.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.1","typeLabel":"null"}],"uniqueKey":"payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"uniqueKey":"recovery","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"\u003cstring>","doc_url":"\u003cstring>","field":"selections[1].quantity"},"payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","quoted_cart_id":2097152,"reason":"travelers_changed"}}},"exampleType":"generated"}},"exampleType":"generated"},"76314fbb-599b-4e49-ab8a-d7ae403c10d7":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"AUTH_REQUIRED","message":"Invalid or expired API key.","doc_url":"https://docs.gojinko.com/authentication/api-keys"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"AUTH_REQUIRED","message":"Invalid or expired API key.","doc_url":"https://docs.gojinko.com/authentication/api-keys"}}}},"exampleType":"examples"}},"exampleType":"examples"},"17efde8e-705b-467f-a0d6-8e23524710e2":{"description":"Payment required — organization balance exhausted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"PAYMENT_REQUIRED","message":"Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup","doc_url":"https://docs.gojinko.com/concepts/errors"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"PAYMENT_REQUIRED","message":"Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup","doc_url":"https://docs.gojinko.com/concepts/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"9342ff50-3565-49a9-8fac-01198770f8f3":{"description":"This payment type is not enabled or access is forbidden. **`PAYMENT_TYPE_NOT_ENABLED`** — This payment type is not enabled for the caller. Choose a type advertised in accepted_payment_types or contact support. **`FORBIDDEN`** — The credential is valid, and this request is refused anyway. Do not rotate the key — it is working. Check that it is entitled to this operation, and on this environment.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.1","typeLabel":"null"}],"uniqueKey":"payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"uniqueKey":"recovery","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"\u003cstring>","doc_url":"\u003cstring>","field":"selections[1].quantity"},"payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","quoted_cart_id":2097152,"reason":"travelers_changed"}}},"exampleType":"generated"}},"exampleType":"generated"},"3afc3ae4-236c-4eb6-8e4c-524fbc8c66dd":{"description":"The trip, or the `quote_id` among its quotes, was not found. Nothing was charged. **`NOT_FOUND`** — No resource with that identifier is visible to this key. Check the identifier. A trip or booking belongs to the key that created it.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"\u003cstring>","doc_url":"\u003cstring>","field":"selections[1].quantity"}}}},"exampleType":"generated"}},"exampleType":"generated"},"100197e3-c733-4285-a24a-ca818bcd4831":{"description":"Payment submission conflicts with an existing attempt. **`TRIP_OWNED_BY_OTHER_PAYMENT`** — Another payment attempt owns this trip. Read the existing attempt and follow its recovery action before paying again. **`IDEMPOTENCY_KEY_REUSED`** — The idempotency key was already used for a different submission. Reuse the original request with this key, or use a new key for a new submission. **`ATTEMPT_IN_PROGRESS`** — A payment attempt is already in progress. Poll the existing attempt and follow recovery.action. **`ATTEMPT_TERMINAL`** — This payment attempt has reached a terminal state. Read its outcome and follow recovery.action before starting another attempt.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.1","typeLabel":"null"}],"uniqueKey":"payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"uniqueKey":"recovery","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"\u003cstring>","doc_url":"\u003cstring>","field":"selections[1].quantity"},"payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","quoted_cart_id":2097152,"reason":"travelers_changed"}}},"exampleType":"generated"}},"exampleType":"generated"},"673229f8-d2f8-4ed2-baf4-ccdffefab3e3":{"description":"The locked quote has expired, so nothing was redeemed and no payment object was created — or the resource the request names is gone. Tell the two apart by `error.code`. **`QUOTE_EXPIRED`** — The quote can no longer be paid, so payment was refused before any payment object was created: either it passed its `expires_at`, or the trip's travelers changed after it was priced (`reason: travelers_changed`; `expires_at` is then the refusal instant). A typed payment refused this way also carries `payment_error` and `recovery`. Call `POST /v1/checkout` again on the same trip — it re-quotes — then mint a new Shared Payment Token against the new `agent_spt_params` and submit that against the new `quote_id`. Nothing was charged. **`GONE`** — The resource this request names existed and no longer does. Re-acquire it — search again, or check out again to re-quote — then retry with the new identifier. Repeating this request with the same one cannot succeed.","content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["QUOTE_EXPIRED"],"isRequired":true,"uniqueKey":"oneOf.0.error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"oneOf.0.error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"oneOf.0.error.doc_url","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"oneOf.0.error","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"oneOf.0.expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"oneOf.0.quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"oneOf.0.quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"oneOf.0.reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"oneOf.0","typeLabel":"object"},{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"oneOf.1.error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"oneOf.1.error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"oneOf.1.error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"oneOf.1.error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"oneOf.1.error","typeLabel":"object"}},"uniqueKey":"oneOf.1","typeLabel":"object"},{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"oneOf.2.error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"oneOf.2.error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"oneOf.2.error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"oneOf.2.error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"oneOf.2.error","typeLabel":"object"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"oneOf.2.payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"oneOf.2.payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"uniqueKey":"oneOf.2.payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"uniqueKey":"oneOf.2.payment_error.oneOf.1","typeLabel":"null"}],"uniqueKey":"oneOf.2.payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"oneOf.2.recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"oneOf.2.recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"uniqueKey":"oneOf.2.recovery","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"oneOf.2.expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"oneOf.2.quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"oneOf.2.quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"oneOf.2.reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"oneOf.2","typeLabel":"object"}],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"QUOTE_EXPIRED","message":"The quote behind this checkout expired at 2026-09-04T12:39:56Z.","doc_url":"https://docs.gojinko.com/concepts/errors"},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","reason":"travelers_changed"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"QUOTE_EXPIRED","message":"The quote behind this checkout expired at 2026-09-04T12:39:56Z.","doc_url":"https://docs.gojinko.com/concepts/errors"},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","reason":"travelers_changed"}}},"exampleType":"examples"}},"exampleType":"examples"},"6d587ee1-4e2b-4a79-90de-2f9978104855":{"description":"Validation error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"BAD_REQUEST","message":"A required field is missing or invalid.","doc_url":"https://docs.gojinko.com/concepts/errors"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"A required field is missing or invalid.","doc_url":"https://docs.gojinko.com/concepts/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"c10d3c41-f8b3-4b06-9e13-ec43cfff4056":{"description":"Rate limit or quota exceeded","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Absent when no interval applies.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Retry after the Retry-After delay.","doc_url":"https://docs.gojinko.com/concepts/errors"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Retry after the Retry-After delay.","doc_url":"https://docs.gojinko.com/concepts/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"88fd1f6b-06f6-4f19-9358-ddfd4503be9c":{"description":"The travel provider rejected the request, or an upstream call failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"UPSTREAM_REJECTED","message":"The request was declined for this offer. Try another offer.","doc_url":"https://docs.gojinko.com/concepts/errors"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"UPSTREAM_REJECTED","message":"The request was declined for this offer. Try another offer.","doc_url":"https://docs.gojinko.com/concepts/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"},"ab4836d2-af98-475f-bbb6-ec7e10c210d6":{"description":"Payment temporarily unavailable. **`TEMPORARILY_UNAVAILABLE`** — Payment submission is temporarily unavailable. Wait for Retry-After when provided and follow recovery.action.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"},"payment_error":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"],"isRequired":true,"uniqueKey":"payment_error.oneOf.0.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"payment_error.oneOf.0.message","typeLabel":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.0","typeLabel":"object"},{"type":"null","properties":{"code":{"type":"string","enum":["CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","CARD_DECLINED","CARD_ALIAS_EXPIRED","PAYMENT_CREDENTIAL_REJECTED","AUTHENTICATION_REQUIRED","AUTHENTICATION_FAILED","AUTHENTICATION_ABANDONED","QUOTE_EXPIRED","ATTEMPT_TERMINAL","PAYMENT_OUTCOME_UNKNOWN","FULFILLMENT_DISPATCH_DELAYED","RECONCILIATION_REQUIRED","TEMPORARILY_UNAVAILABLE"]},"message":{"type":"string"}},"required":["code","message"],"uniqueKey":"payment_error.oneOf.1","typeLabel":"null"}],"uniqueKey":"payment_error","typeLabel":"object | null"},"recovery":{"type":"object","properties":{"action":{"type":"string","enum":["poll","authenticate","retry_same_key","retry_new_key","recheckout","contact_support","stop"],"description":"The next step. `authenticate`: when `authentication` is present, open `authentication.url` before `authentication.expires_at`. For a Shared Payment Token (`spt`), first read the token's `next_action.use_stripe_sdk.value` with your own Stripe secret key and append it unchanged: open `authentication.url + \"#hv=\" + \u003cvalue>`, or call `stripe.handleNextAction({ hashedValue })` with Stripe.js on your own page. Then poll `GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}` until `payment_status` is none of `requires_authentication`, `cancelling` or `pending`.","isRequired":true,"uniqueKey":"recovery.action","typeLabel":"enum\u003cstring>"},"replacement_credential_required":{"type":"boolean","isRequired":true,"uniqueKey":"recovery.replacement_credential_required","typeLabel":"boolean"}},"required":["action","replacement_credential_required"],"uniqueKey":"recovery","typeLabel":"object"},"expires_at":{"type":"string","description":"The instant the refused quote expired (RFC 3339). For a deadline lapse this is the past deadline; when `reason` is `travelers_changed` it is the instant of the refusal.","example":"2026-09-04T12:39:56Z","uniqueKey":"expires_at","typeLabel":"string"},"quote_id":{"type":"string","description":"The quote that was refused — the same `quote_id` the trip and checkout responses carry, so a caller holding several can tell which one this refusal is about.","example":"2097152","uniqueKey":"quote_id","typeLabel":"string"},"quoted_cart_id":{"type":"number","description":"Deprecated: use `quote_id` instead. The same quote as an integer.","example":2097152,"deprecated":true,"uniqueKey":"quoted_cart_id","typeLabel":"number"},"reason":{"type":"string","enum":["travelers_changed"],"description":"Present when the quote was invalidated because the trip's travelers changed after it was priced (`travelers_changed`). Absent for a plain deadline lapse. Either way the recovery is the same: call `POST /v1/checkout` again to re-quote, then pay against the new quote.","example":"travelers_changed","uniqueKey":"reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"code":"BAD_REQUEST","message":"\u003cstring>","doc_url":"\u003cstring>","field":"selections[1].quantity"},"payment_error":{"code":"CREDENTIAL_FORMAT_INVALID","message":"\u003cstring>"},"recovery":{"action":"poll","replacement_credential_required":true},"expires_at":"2026-09-04T12:39:56Z","quote_id":"2097152","quoted_cart_id":2097152,"reason":"travelers_changed"}}},"exampleType":"generated"}},"exampleType":"generated"},"40dae6f5-63fb-4cdf-8843-3eaca733a48e":{"description":"The travel provider did not answer in time","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["INVALID_SEGMENTS_TO_EXCHANGE","PARTIAL_EXCHANGE_UNSUPPORTED","LEG_ALREADY_DEPARTED","DEPARTURE_DATE_IN_PAST","LEG_DATES_OUT_OF_ORDER","INVALID_EXCHANGE_REQUEST","NOT_EXCHANGEABLE","CREDENTIAL_FORMAT_INVALID","PAYMENT_TYPE_NOT_ENABLED","PAYMENT_CREDENTIAL_INVALID","TRIP_OWNED_BY_OTHER_PAYMENT","IDEMPOTENCY_KEY_REUSED","ATTEMPT_IN_PROGRESS","ATTEMPT_TERMINAL","TEMPORARILY_UNAVAILABLE","AUTH_REQUIRED","PAYMENT_REQUIRED","RATE_LIMITED","BAD_REQUEST","FORBIDDEN","NOT_FOUND","CONFLICT","GONE","QUOTE_PENDING","QUOTE_EXPIRED","TRIP_EXPIRED","TRIP_STATE_CONFLICT","OFFER_EXPIRED","OFFER_UNAVAILABLE","MISSING_CUSTOMER_DETAILS","INVALID_PHONE_NUMBER","INVALID_FLIGHT_NUMBER","CURRENCY_UNSUPPORTED","HOTEL_NAME_LOW_CONFIDENCE","DESTINATION_LOW_CONFIDENCE","UPSTREAM_REJECTED","UPSTREAM_UNAVAILABLE","UPSTREAM_TIMEOUT","UPSTREAM_ERROR","INTERNAL"],"description":"What went wrong, as a stable machine-readable code. This is a closed set — branch on it rather than on `message`, which is prose and may change. New codes arrive in a minor version, so treat an unknown one as its HTTP status. A code can also stop being emitted: it leaves this set in a minor version, named in the changelog, and a branch you wrote for it goes unreached rather than wrong.","example":"BAD_REQUEST","isRequired":true,"uniqueKey":"error.code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"What went wrong, in prose. These codes always carry the same message, and it never includes text from a supplier: `RATE_LIMITED` — \"Too many requests. Retry after the Retry-After delay.\"; `OFFER_EXPIRED` — \"This offer has expired. Search again.\"; `OFFER_UNAVAILABLE` — \"This offer is no longer available. Search again.\"; `UPSTREAM_REJECTED` — \"The request was declined for this offer. Try another offer.\"; `UPSTREAM_UNAVAILABLE` — \"The service is temporarily unavailable. Retry after the Retry-After delay.\"; `UPSTREAM_TIMEOUT` — \"The request timed out before a result was available. Retry the request.\"; `UPSTREAM_ERROR` — \"The request could not be completed.\".","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"doc_url":{"type":"string","uniqueKey":"error.doc_url","typeLabel":"string"},"field":{"type":"string","description":"On a 400 `BAD_REQUEST` that names one refused input: the path of that field in your request, e.g. `selections[1].quantity` for the second selection of a `select_ancillaries` call. Absent when the refusal names no single field.","example":"selections[1].quantity","uniqueKey":"error.field","typeLabel":"string"}},"required":["code","message"],"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"required":["error"],"uniqueKey":"","typeLabel":"object"},"example":{"error":{"code":"UPSTREAM_TIMEOUT","message":"The request timed out before a result was available. Retry the request.","doc_url":"https://docs.gojinko.com/concepts/errors"}},"examples":{"Example":{"title":"Example","value":{"error":{"code":"UPSTREAM_TIMEOUT","message":"The request timed out before a result was available. Retry the request.","doc_url":"https://docs.gojinko.com/concepts/errors"}}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"39839d48-3c13-4f4e-a6d4-c19a28337289":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","scopes":[],"schemeName":"ApiKeyAuth"}},"ca28de3f-4159-4a27-b812-7e0c55dfec51":{"BearerAuth":{"type":"http","scheme":"bearer","scopes":[],"schemeName":"BearerAuth"}}},"servers":{"6c2e2c14-8667-4ef1-a6c7-d1e7fb982378":{"url":"https://api.gojinko.com","description":"Production"},"0b2c8592-7b6b-4acc-9351-2a69f3e0f42a":{"url":"https://api.sandbox.gojinko.com","description":"Sandbox"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"X-API-Key","scopes":[],"schemeName":"ApiKeyAuth"},"schema":{"title":"X-API-Key","type":"string","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"ApiKeyAuth","name":"X-API-Key"}],"title":"ApiKeyAuth"},{"schemes":[{"scheme":{"type":"http","scheme":"bearer","scopes":[],"schemeName":"BearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Bearer authentication header of the form `Bearer \u003ctoken>`, where `\u003ctoken>` is your auth token.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"BearerAuth","name":"Authorization"}],"title":"BearerAuth"}]},"originalFileLocation":"api-reference/public-api.yaml"},"subdomain":"jinko-dev","siteName":"Jinko Platform","title":"agent-payment submit - Jinko Platform","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-06T04:07:25.516Z","originalFileLocation":"api/agent-payment/submit.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Submit SPT payments; card submissions must use the payment hostname and are refused here\">\u003cmeta data-mint-head name=\"application-name\" content=\"Jinko Platform\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"agent-payment submit - Jinko Platform\">\u003cmeta data-mint-head property=\"og:description\" content=\"Submit SPT payments; card submissions must use the payment hostname and are refused here\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Jinko Platform\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.dev.gojinko.com/api/agent-payment/submit\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://jinko-dev.mintlify.site/_mintlify/api/og/v2?division=Trip+%26+Payment\u0026amp;title=agent-payment+submit\u0026amp;description=Submit+SPT+payments%3B+card+submissions+must+use+the+payment+hostname+and+are+refused+here\u0026amp;theme=d8471b1916fc5bd660c4c758\u0026amp;signature=2fef385c9b572212354aa1a04f7a202898ba125d528d969c3b8771d2ae091b9e\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"agent-payment submit - Jinko Platform\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Submit SPT payments; card submissions must use the payment hostname and are refused here\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://jinko-dev.mintlify.site/_mintlify/api/og/v2?division=Trip+%26+Payment\u0026amp;title=agent-payment+submit\u0026amp;description=Submit+SPT+payments%3B+card+submissions+must+use+the+payment+hostname+and+are+refused+here\u0026amp;theme=d8471b1916fc5bd660c4c758\u0026amp;signature=2fef385c9b572212354aa1a04f7a202898ba125d528d969c3b8771d2ae091b9e\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/jinko-dev/jotmHl7NmaCERw_m/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Jinko Platform\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#FF6363\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.dev.gojinko.com/api/agent-payment/submit\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api/agent-payment/submit.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.dev.gojinko.com/#organization\",\"name\":\"Jinko Platform\",\"url\":\"https://docs.dev.gojinko.com\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/jinko-dev/k6P2DyAYQF0FPJQi/logo/jinko-logo.png?fit=max\u0026auto=format\u0026n=k6P2DyAYQF0FPJQi\u0026q=85\u0026s=785a20dc553a2698bfffad325d1198d0\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.dev.gojinko.com#website\",\"name\":\"Jinko Platform\",\"url\":\"https://docs.dev.gojinko.com\",\"publisher\":{\"@id\":\"https://docs.dev.gojinko.com/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.dev.gojinko.com/api/agent-payment/submit#webpage\",\"url\":\"https://docs.dev.gojinko.com/api/agent-payment/submit\",\"name\":\"agent-payment submit\",\"description\":\"Submit SPT payments; card submissions must use the payment hostname and are refused here\",\"dateModified\":\"2026-11-06T04:07:25.516Z\",\"isPartOf\":{\"@id\":\"https://docs.dev.gojinko.com#website\"},\"breadcrumb\":{\"@id\":\"https://docs.dev.gojinko.com/api/agent-payment/submit#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.dev.gojinko.com/api/agent-payment/submit#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Trip \u0026 Payment\",\"item\":\"https://docs.dev.gojinko.com/api/trip\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"agent-payment submit\",\"item\":\"https://docs.dev.gojinko.com/api/agent-payment/submit\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.dev.gojinko.com/api/agent-payment/submit#apireference\",\"headline\":\"agent-payment submit\",\"name\":\"agent-payment submit\",\"description\":\"Submit SPT payments; card submissions must use the payment hostname and are refused here\",\"url\":\"https://docs.dev.gojinko.com/api/agent-payment/submit\",\"mainEntityOfPage\":{\"@id\":\"https://docs.dev.gojinko.com/api/agent-payment/submit#webpage\"},\"dateModified\":\"2026-11-06T04:07:25.516Z\",\"publisher\":{\"@id\":\"https://docs.dev.gojinko.com/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.dev.gojinko.com#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Jinko Platform\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Jinko Platform","nav":{"global":null,"tabs":[{"tab":"Documentation","pages":[{"title":"Documentation","href":"/introduction"}]},{"tab":"MCP","pages":[{"title":"MCP","href":"/tools/overview"}]},{"tab":"CLI","pages":[{"title":"CLI","href":"/cli/overview"}]},{"tab":"API reference","groups":[{"group":"Introduction","pages":[{"title":"API reference","href":"/api-reference/introduction"}]},{"group":"Travel Demand","pages":[{"group":"Destination","pages":[{"title":"destination","sidebarTitle":"/v1/destination","openapi":"api-reference/public-api.yaml GET /v1/destination","href":"/api/destination"},{"title":"destination trend","sidebarTitle":"/v1/destination/trend","openapi":"api-reference/public-api.yaml GET /v1/destination/trend","href":"/api/destination/trend"}]},{"group":"Market","pages":[{"title":"market","sidebarTitle":"/v1/market","openapi":"api-reference/public-api.yaml GET /v1/market","href":"/api/market"},{"title":"market trend","sidebarTitle":"/v1/market/trend","openapi":"api-reference/public-api.yaml GET /v1/market/trend","href":"/api/market/trend"}]},{"group":"Audience","pages":[{"title":"audience","sidebarTitle":"/v1/audience","openapi":"api-reference/public-api.yaml GET /v1/audience","href":"/api/audience"},{"title":"audience trend","sidebarTitle":"/v1/audience/trend","openapi":"api-reference/public-api.yaml GET /v1/audience/trend","href":"/api/audience/trend"}]},{"group":"Trend","pages":[{"title":"trend","sidebarTitle":"/v1/trend","openapi":"api-reference/public-api.yaml GET /v1/trend","href":"/api/trend"}]}]},{"group":"Flights","pages":[{"group":"Discovery","pages":[{"title":"find-destination","sidebarTitle":"/v1/find_destination","openapi":"api-reference/public-api.yaml POST /v1/find_destination","href":"/api/find-destination"},{"title":"flight-calendar","sidebarTitle":"/v1/flight_calendar","openapi":"api-reference/public-api.yaml POST /v1/flight_calendar","href":"/api/flight-calendar"},{"title":"find-dates","sidebarTitle":"/v1/find_dates","openapi":"api-reference/public-api.yaml POST /v1/find_dates","href":"/api/find-dates"},{"title":"lowest-fare","sidebarTitle":"/v1/lowest_fare","openapi":"api-reference/public-api.yaml POST /v1/lowest_fare","href":"/api/lowest-fare"},{"title":"price-monitoring","sidebarTitle":"/v1/price_monitoring","openapi":"api-reference/public-api.yaml POST /v1/price_monitoring","href":"/api/price-monitoring"},{"title":"flight-price-advice","sidebarTitle":"/v1/flight_price_advice","openapi":"api-reference/public-api.yaml POST /v1/flight_price_advice","href":"/api/flight-price-advice"}]},{"group":"Search","pages":[{"title":"flight-search","sidebarTitle":"/v1/flight_search","openapi":"api-reference/public-api.yaml POST /v1/flight_search","href":"/api/flight-search"},{"title":"flight-award-search (preview)","sidebarTitle":"/v1/flight_award_search (preview)","openapi":"api-reference/public-api-dev.yaml POST /v1/flight_award_search","href":"/api/flight-award-search"}]},{"group":"Manage","pages":[{"title":"refund check","sidebarTitle":"/v1/refund_check","openapi":"api-reference/public-api.yaml POST /v1/refund_check","deprecated":true,"href":"/api/refund/check"},{"title":"refund commit","sidebarTitle":"/v1/refund_commit","openapi":"api-reference/public-api.yaml POST /v1/refund_commit","deprecated":true,"href":"/api/refund/commit"},{"title":"refund status","sidebarTitle":"/v1/refund_status","openapi":"api-reference/public-api.yaml POST /v1/refund_status","deprecated":true,"href":"/api/refund/status"},{"title":"exchange shop","sidebarTitle":"/v1/exchange_shop","openapi":"api-reference/public-api.yaml POST /v1/exchange_shop","href":"/api/exchange/shop"},{"title":"exchange price","sidebarTitle":"/v1/exchange_price","openapi":"api-reference/public-api.yaml POST /v1/exchange_price","href":"/api/exchange/price"},{"title":"exchange commit","sidebarTitle":"/v1/exchange_commit","openapi":"api-reference/public-api.yaml POST /v1/exchange_commit","href":"/api/exchange/commit"},{"title":"exchange status","sidebarTitle":"/v1/exchange_status","openapi":"api-reference/public-api.yaml POST /v1/exchange_status","href":"/api/exchange/status"},{"title":"flight-refund-preview","sidebarTitle":"/v1/flight_refund_preview","openapi":"api-reference/public-api.yaml POST /v1/flight_refund_preview","href":"/api/flight-refund-preview"},{"title":"flight-refund-commit","sidebarTitle":"/v1/flight_refund_commit","openapi":"api-reference/public-api.yaml POST /v1/flight_refund_commit","href":"/api/flight-refund-commit"},{"title":"flight-refund-status","sidebarTitle":"/v1/flight_refund_status","openapi":"api-reference/public-api.yaml POST /v1/flight_refund_status","href":"/api/flight-refund-status"}]}]},{"group":"Hotels","pages":[{"title":"hotel-search","sidebarTitle":"/v1/hotel_search","openapi":"api-reference/public-api.yaml POST /v1/hotel_search","href":"/api/hotel-search"},{"title":"hotel-details","sidebarTitle":"/v1/hotel_details/{hotel_id}","openapi":"api-reference/public-api.yaml GET /v1/hotel_details/{hotel_id}","href":"/api/hotel-details"},{"title":"hotel-reviews","sidebarTitle":"/v1/hotel_reviews/{hotel_id}","openapi":"api-reference/public-api.yaml GET /v1/hotel_reviews/{hotel_id}","href":"/api/hotel-reviews"},{"title":"hotel-cancel","sidebarTitle":"/v1/hotel_cancel","openapi":"api-reference/public-api.yaml POST /v1/hotel_cancel","deprecated":true,"href":"/api/hotel-cancel"},{"title":"hotel-cancel-preview","sidebarTitle":"/v1/hotel_cancel_preview","openapi":"api-reference/public-api.yaml POST /v1/hotel_cancel_preview","href":"/api/hotel-cancel-preview"},{"title":"hotel-cancel-commit","sidebarTitle":"/v1/hotel_cancel_commit","openapi":"api-reference/public-api.yaml POST /v1/hotel_cancel_commit","href":"/api/hotel-cancel-commit"},{"title":"hotel-cancel-status","sidebarTitle":"/v1/hotel_cancel_status","openapi":"api-reference/public-api.yaml POST /v1/hotel_cancel_status","href":"/api/hotel-cancel-status"}]},{"group":"AI","pages":[{"group":"Hotel search","pages":[{"title":"hotel-ai-search","sidebarTitle":"/v1/hotel_ai_search","openapi":"api-reference/public-api.yaml POST /v1/hotel_ai_search","href":"/api/hotel-ai-search"},{"title":"hotel-ai-search-task","sidebarTitle":"/v1/hotel_ai_search/tasks/{task_id}","openapi":"api-reference/public-api.yaml GET /v1/hotel_ai_search/tasks/{task_id}","href":"/api/hotel-ai-search-task"},{"title":"hotel-ai-search-events","sidebarTitle":"/v1/hotel_ai_search/tasks/{task_id}/events","openapi":"api-reference/public-api.yaml GET /v1/hotel_ai_search/tasks/{task_id}/events","href":"/api/hotel-ai-search-events"},{"title":"hotel-ai-search-cancel","sidebarTitle":"/v1/hotel_ai_search/tasks/{task_id}:cancel","openapi":"api-reference/public-api.yaml POST /v1/hotel_ai_search/tasks/{task_id}:cancel","href":"/api/hotel-ai-search-cancel"}]}]},{"group":"Cars","pages":[{"title":"car-search","sidebarTitle":"/v1/car_search","openapi":"api-reference/public-api.yaml POST /v1/car_search","href":"/api/car-search"},{"title":"car-cancel-preview","sidebarTitle":"/v1/car_cancel_preview","openapi":"api-reference/public-api.yaml POST /v1/car_cancel_preview","href":"/api/car-cancel-preview"},{"title":"car-cancel-commit","sidebarTitle":"/v1/car_cancel_commit","openapi":"api-reference/public-api.yaml POST /v1/car_cancel_commit","href":"/api/car-cancel-commit"},{"title":"car-cancel-status","sidebarTitle":"/v1/car_cancel_status","openapi":"api-reference/public-api.yaml POST /v1/car_cancel_status","href":"/api/car-cancel-status"}]},{"group":"Trip \u0026 Payment","pages":[{"title":"trip","sidebarTitle":"/v1/trip","openapi":"api-reference/public-api.yaml POST /v1/trip","href":"/api/trip"},{"group":"Ancillaries","pages":[{"title":"select-ancillaries","sidebarTitle":"/v1/select_ancillaries","openapi":"api-reference/public-api.yaml POST /v1/select_ancillaries","href":"/api/select-ancillaries"},{"title":"trip ancillaries","sidebarTitle":"/v1/trip/{trip_id}/ancillaries","openapi":"api-reference/public-api.yaml GET /v1/trip/{trip_id}/ancillaries","href":"/api/trip/ancillaries"}]},{"title":"checkout","sidebarTitle":"/v1/checkout","description":"Checkout a trip, returns a checkout URL the user opens to pay, plus the Shared Payment Token params an agent can use to pay programmatically","openapi":"api-reference/public-api.yaml POST /v1/checkout","href":"/api/checkout"},{"title":"agent-payment submit","sidebarTitle":"/v1/agent_payment/submit","openapi":"api-reference/public-api.yaml POST /v1/agent_payment/submit","href":"/api/agent-payment/submit"},{"title":"trip-status","sidebarTitle":"/v1/trip/{trip_id}","description":"Fetch the full lifecycle state of a trip, items, travelers, quote, fulfillment, and any booking references","openapi":"api-reference/public-api.yaml GET /v1/trip/{trip_id}","href":"/api/trip-status"},{"title":"get-booking","sidebarTitle":"/v1/get_booking","openapi":"api-reference/public-api.yaml POST /v1/get_booking","href":"/api/get-booking"}]},{"group":"Marketing claim","tag":"Preview","pages":[{"title":"best-price-guarantee","sidebarTitle":"/v1/best_price_guarantee","openapi":"api-reference/public-api.yaml POST /v1/best_price_guarantee","href":"/api/best-price-guarantee"},{"title":"best-price-guarantee-status","sidebarTitle":"/v1/best_price_guarantee/{id}","openapi":"api-reference/public-api.yaml GET /v1/best_price_guarantee/{id}","href":"/api/best-price-guarantee-status"}]},{"group":"Webhooks","pages":[{"title":"webhooks register","sidebarTitle":"/v1/webhooks","openapi":"api-reference/public-api.yaml POST /v1/webhooks","href":"/api/webhooks/register"},{"title":"webhooks list","sidebarTitle":"/v1/webhooks","openapi":"api-reference/public-api.yaml GET /v1/webhooks","href":"/api/webhooks/list"},{"title":"webhooks get","sidebarTitle":"/v1/webhooks/{id}","openapi":"api-reference/public-api.yaml GET /v1/webhooks/{id}","href":"/api/webhooks/get"},{"title":"webhooks delete","sidebarTitle":"/v1/webhooks/{id}","openapi":"api-reference/public-api.yaml DELETE /v1/webhooks/{id}","href":"/api/webhooks/delete"},{"title":"webhooks test","sidebarTitle":"/v1/webhooks/{id}/test","openapi":"api-reference/public-api.yaml POST /v1/webhooks/{id}/test","href":"/api/webhooks/test"},{"title":"webhooks deliveries","sidebarTitle":"/v1/webhooks/{id}/deliveries","openapi":"api-reference/public-api.yaml GET /v1/webhooks/{id}/deliveries","href":"/api/webhooks/deliveries"},{"title":"webhooks replay","sidebarTitle":"/v1/webhooks/{id}/deliveries/{delivery_id}/replay","openapi":"api-reference/public-api.yaml POST /v1/webhooks/{id}/deliveries/{delivery_id}/replay","href":"/api/webhooks/replay"}]},{"group":"Other endpoints","pages":[{"title":"flight-ai-search","sidebarTitle":"/v1/flight_ai_search","openapi":"api-reference/public-api.yaml POST /v1/flight_ai_search","href":"/api/flight-ai-search"},{"title":"flight-ai-search-cancel","sidebarTitle":"/v1/flight_ai_search/tasks/{task_id}:cancel","openapi":"api-reference/public-api.yaml POST /v1/flight_ai_search/tasks/{task_id}:cancel","href":"/api/flight-ai-search-cancel"},{"title":"flight-ai-search-events","sidebarTitle":"/v1/flight_ai_search/tasks/{task_id}/events","openapi":"api-reference/public-api.yaml GET /v1/flight_ai_search/tasks/{task_id}/events","href":"/api/flight-ai-search-events"},{"title":"flight-ai-search-task","sidebarTitle":"/v1/flight_ai_search/tasks/{task_id}","openapi":"api-reference/public-api.yaml GET /v1/flight_ai_search/tasks/{task_id}","href":"/api/flight-ai-search-task"},{"title":"flight-schedule","sidebarTitle":"/v1/flight_schedule","openapi":"api-reference/public-api.yaml POST /v1/flight_schedule","href":"/api/flight-schedule"},{"title":"trip payment-attempts","sidebarTitle":"/v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}","openapi":"api-reference/public-api.yaml GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id}","href":"/api/trip/payment-attempts"}]}]}]},"basePath":"","title":"agent-payment submit - Jinko Platform","buildId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","deploymentId":"dpl_8LJbrAiZvr1K98WQNZXCyY5AvT34","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-i2a3QZ8E.js","utils-ChLwp8m0.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DRktVTDc.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-CA2pEs4T.js","snippetPresets-ClQ6XrKD.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-Ct_Lv36y.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-Cn2PYw9e.js","shallow-rkyymjXQ.js","getApiPlaygroundDisplay-BB9vkXtE.js","CodeSnippet-Bm5RU7m1.js","CodeSnippets-BgU9Deuz.js","Page-BUDYNlhG.js","getPastedJson-BD-6NNum.js","icon-8Z6tud2e.js","MethodPill-Tuzr4g3V.js","DuplicateIcon-0ceWFYhN.js","createIcon-FBXow_ST.js","DynamicMarkdown-CD8713Yy.js","SectionHeading-7zgzQbH-.js","axios-vUo_bRtp.js","Markdown-D7Ofw1oz.js","clsx-eKJ4rcii.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CwjSCXIK.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-9EK5IAXV.js"]}