Skip to main content

When to use

Use this guide to integrate raw customer cards or virtual credit cards (VCCs) through the REST API, using the public API 0.18.x contract. Start with a trip containing the selected items and travelers; see Flight booking. Checkout discovery → typed payment submission → read the outcome → follow its recovery action.

Discover what the tenant may use

Call checkout with your tenant-bound booking key. The examples use placeholders only.
An illustrative response excerpt for a tenant enabled for VCC payments:
accepted_payment_types lists only presently usable combinations. Each entry has type (spt or card), optional card_kinds (customer_card or vcc), required headers and fields, and authentication (customer_handoff or unavailable). A customer-card entry can advertise customer_handoff; a VCC has no handoff. Do not cache this discovery. Read it on each checkout and use the returned quote ID and deadline. Never send card data speculatively: submit a card only when discovery lists card and the intended card kind. An absent combination is unavailable, even if it worked before.

Submit a card payment

Send a typed body to POST /v1/agent_payment/submit. Authenticate with a tenant-bound booking key (jnk_…), sent as X-API-Key or as Authorization: Bearer; OAuth/JWT bearer tokens are refused for typed bodies. Idempotency-Key is required. This curl template sends the body through standard input. Keep real card data out of shell history and command arguments; production requests belong in your secure backend.
Replace 123 with the discovered quoted_cart_id and the expiration with the credential’s expiration. Use card_kind: "customer_card" for a customer card. billing_details is optional inside payment. For a shared payment token (SPT), the typed body is:
The legacy flat SPT body is unchanged. Use one idempotency key per intended attempt. The first accepted request wins. Replay the same accepted request with the same key to recover its outcome. The key is compared against the safe immutable fields (trip, quoted cart, payment type, card kind, amount and currency): changing one of those with the same key returns 409 idempotency_key_reused. Card credentials are deliberately not part of that comparison, so a replay with the same key and different card details returns the first accepted attempt’s outcome rather than a new attempt; send a new key for a new credential. A request rejected before acceptance (400 credential_format_invalid) does not consume the key — correct the request and replay it with the same key, unless the Idempotency-Key itself was rejected, in which case send a valid key. A timeout is not permission to create a new attempt. Follow recovery.action. Send a replacement credential with a new key only when the outcome permits it, cleanup is complete, and the quote is still valid. Otherwise recheckout when instructed.

Read the outcome

The typed submit response is a PaymentAttemptOutcome: 200 means a known outcome, including a decline. It does not mean the payment or booking succeeded. 202 means pending. Wait for the Retry-After interval, then poll the attempt:
{trip_id} path parameters accept either trip_<n> or <n> (for example, trip_123 or 123). Any other format returns 400 with the fixed message invalid trip_id. Honor the returned polling interval (Retry-After / retry_after_seconds). Keep reading the same attempt while its action is poll, including during cancellation or an unknown provider outcome. Do not submit a second payment to resolve a pending booking.

Customer authentication handoff

authentication is returned only for customer_card attempts in requires_authentication, with recovery.action: "authenticate". Send the customer to the returned authentication.url unchanged before authentication.expires_at. Never parse or reconstruct it. The link points to Jinko’s web app and has this shape:
The page completes 3DS on the existing PaymentIntent and shows the server-verified outcome. Keep polling GET /v1/trip/{trip_id}/payment_attempts/{payment_attempt_id} while the customer authenticates. VCC attempts never receive an authentication handoff. After the customer returns, read the attempt. A browser return is not proof of authorization. Closing the browser before the deadline does not itself prove failure; poll. A verified authentication failure requires cleanup. Authentication still incomplete at the deadline becomes abandoned; poll cleanup, then recheckout when instructed.

VCC policy

VCCs have no customer authentication handoff. If a VCC needs authentication, do not open a hosted payment flow or ask a traveler to authenticate it. Obtain a replacement credential that can complete without a handoff. Wait until the attempt permits replacement and cleanup is complete; then use a new key on a valid quote, or recheckout as directed. Fulfillment never falls back to hosted payment for a VCC.

Outcome codes and recovery

Always obey the returned recovery action. A code alone does not establish that cleanup has finished or the quote is still usable. The public code meanings and caller actions are: For payment_credential_rejected, “same” means replacement + new key on a valid quote once quiescent. Quiescent means the earlier attempt has finished cleanup and the returned recovery action permits another attempt.

Failure table

Statuses can change during cleanup. Read the latest outcome and its recovery action before acting.

Money outcomes after booking

money reports authorized, captured, released, refunded, and externally_reimbursed as Money objects with display. Use display for presentation. Read resolution_status (pending, resolved, manual_review, external_reimbursement_pending, or externally_reimbursed) and refund_reference when available; missing amounts are not evidence of zero money movement.
  • Definitive booking failure before capture: the authorization is voided and released; the payment becomes cancelled after cleanup.
  • Definitive booking failure after capture: the captured amount is refunded; read refunded and resolution_status: "resolved".
  • Partial delivery: exactly the booked items are captured, with the remainder released; booking_status is partial.
  • Refund to an expired or cancelled card: operations settles the refund outside the card network. resolution_status is external_reimbursement_pending until settled, then externally_reimbursed; read the externally_reimbursed amount and refund_reference. Do not treat a failed refund as reimbursement completed or start another payment.
  • Result cannot be verified: reconciliation_required / manual_review; contact support. Jinko does not guess whether money moved or a booking succeeded.

Security and data handling

Send credentials only from your secure backend over HTTPS. Raw card data must never pass through prompts, MCP, CLI arguments, logs, traces, analytics, support tickets, or stored request bodies. The examples contain placeholders, not usable card credentials. Jinko keeps identifiers only for the payment flow, not raw PAN or CVC. Keep attempt, trip, quote, and request identifiers for recovery and support. Never include the card data when reporting an issue. Jinko handles card data in transit. No storage does not mean “PCI-free”: account for Jinko’s payment processing and your integration in the applicable PCI assessment.

Activation

Card kinds are disabled per tenant by default. Arrange enablement with Jinko, then confirm availability through checkout discovery. Enabling a tenant does not make every combination usable for every checkout. MCP and CLI remain SPT-only. Use the typed REST contract for raw customer cards and VCCs. See Errors & troubleshooting for the payment code reference.