Skip to content

Checkout sessions

A checkout session is the handoff between your trusted order system and the buyer experience. Create it on your server with POST /api/checkout-sessions. The public contract returns both checkout_url and embed_url, so one session contract supports the hosted and embedded choices.

Request fields are strict: an unrecognized top-level property, or an unrecognized property within an items entry, returns 422 Unprocessable Entity. Send only the documented fields and field names.

  • Read amount, currency, line items, and merchant identity from your own trusted order record.
  • Authenticate with the credential alternative declared for the operation.
  • Supply Idempotency-Key when retrying session creation.
  • Store the returned checkout-session identifier with your order.
  • Supply allowed_origins when the buyer experience will run on merchant-owned pages.

The buyer receives a session identifier or returned checkout URL, never the merchant secret. The public session read is buyer-safe and returns no secrets. Do not allow the browser to become the authority for price, currency, line items, or merchant ownership.

Choose Hosted Checkout or Embedded Checkout after session creation. The same session contract can be mounted with the published maxanapay.js when its current rail and capability limits fit the checkout.

A session expires, and its clock starts when you create it, not when the buyer arrives. expires_in_minutes sets the lifetime: omit it and the session lasts 30 minutes, or send any whole number from 5 to 1440 — five minutes to a full day. Anything outside that range is refused with 422 naming the field.

Choose it against the page the buyer will be looking at rather than against the call you are making. A session created while a checkout page loads spends its life while the buyer reads and fills the page in; one created when the buyer presses Pay starts whole. The default suits the second and can be short for the first.

An expired session cannot start a new payment, and the buyer’s page is where that surfaces: the API answers 400 with checkout_session_id has expired and the SDK reports it as session_expired, which is not retryable. See the SDK error vocabulary. A session is immutable, so there is nothing to extend — create another one and mount that.

Expiry does not strand a payment the buyer already approved. The session clock gates the buyer’s page and the anonymous capture it makes, not an authenticated one: if the buyer approved and only the capture never followed, the merchant — or a channel naming the merchant with X-Merchant-Id — can still complete it with POST /api/payments/orders/{order_id}/capture, whose authenticated path is governed by the order’s state, not the session’s clock. An approved order does not have to be abandoned when its session expires.

When your checkout has already calculated shipping, send shipping_amount_cents with shipping_address; the item total plus shipping must equal amount. The authenticated merchant-facing creation response returns both stored values. The buyer-facing public session response returns shipping_amount_cents but does not return shipping_address.

A checkout session is immutable buyer state, not a cart-update API. The buyer cannot change its merchant, amount, currency, or line items, and a browser callback is not proof of capture. Create a replacement session when trusted order facts change.