Skip to main content
A checkout session moves through a small set of statuses from creation to a final outcome. Use these statuses — never gateway_response_code — to drive your own logic.

Statuses

  • pending → processing — the shopper submits payment; a second submission while the first is in flight is rejected.
  • processing → completed / failed — the charge resolves.
  • pending → expired — the TTL elapses before the shopper pays.
  • pending → cancelled — you cancel the session while it’s still pending.
  • processing → pending — the payment service was briefly unreachable; nothing was charged, and the shopper can retry on the same session.
  • Same order_reference, same amount and currency, within the session TTL returns this same session as long as it can still be paid (pending, processing, or completed) — see Replay and retries below for the full rule, including what happens on a terminal session or a changed amount.

Expiry (TTL)

Set ttl_minutes on create (an integer from 5–60). If you omit it, the session uses your environment’s default: 10 minutes in production, 25 minutes in sandbox — sandbox is shorter than production so a session can’t outlive the card token it binds. Since this also bounds how long order_reference deduplicates a retry (see Replay and retries below), set ttl_minutes explicitly rather than relying on the default, especially in production. A session that reaches its TTL without a completed payment moves to expired. An expired session can’t be paid — create a new session (with a new or the same order_reference, see Replay below) if the shopper wants to try again. See Handle expired checkout sessions for the exact redirect signal and recovery steps.
Retention: a session record exists for its TTL plus a short grace buffer, then is no longer retrievable by GET. Your own order records — and the gateway’s transaction record, once a charge happens — are the durable source of truth, not the checkout session itself.

Merchant cancellation

Cancel a session from your server (for example, if the shopper abandons your cart) with your secret key, via the cancel endpoint:
Cancelling is idempotent while the session is still pending — and calling it again on an already-cancelled session is also idempotent. If the session has already moved to processing or another terminal status, the cancel request returns a 409 — you can’t cancel a session that’s already been submitted for payment or already reached a final state. See Resolve checkout cancellation conflicts for the full decision table.
A shopper closing the tab or clicking their browser’s back button does not cancel the session — it stays pending until it expires. If you need it cancelled immediately, call the cancel endpoint from your own server.

Replay and retries

Sending POST /api/v1/checkout/sessions again with the same order_reference (for the same merchant, within the original session’s TTL) either returns the existing session, rejects the retry, or creates a fresh one — depending on whether the original session can still be paid, and whether the amount and currency match. The table below covers every situation you’ll actually hit: See Prevent duplicate sessions and double payments for the full walkthrough. Retrying after a decline, cancellation, or expiry is different: those sessions are terminal, so the reference is released automatically and the next create with the same order_reference starts a genuinely new session — you don’t need to mint a new order_reference for it to work, though using one keeps your own tracking cleaner. Either way, the shopper can’t retry a card on the old session itself.

Next steps

Verify the payment result

Confirm the outcome server-side before fulfilling.

Customize checkout

Line items, shopper details, branding, and more.

Brand the payment page

Colours, fonts, logo, and light/dark mode.

Handle failures

Ten common failure scenarios and what to do for each.
Last modified on September 15, 2026