GitHub

API reference

Checkout sessions

A payment request plus the hand-back — the only part of checkout that crosses between two organisations.

DRAFT

A session is a payment request plus the two things a merchant flow needs and a bare link does not: where to send the payer back, and where to notify the merchant.


POST /checkout/sessions

Requires a member credential.

{
  "request_reference": "7fk2m9pq3vx8",
  "success_url": "https://store.example.com/thanks?order=10482",
  "cancel_url": "https://store.example.com/cart",
  "webhook_url": "https://store.example.com/hooks/path",
  "expires_at": "2026-09-09T10:30:00Z"
}
{
  "id": "cs_4b81f2c7",
  "status": "open",
  "request_reference": "7fk2m9pq3vx8",
  "success_url": "https://store.example.com/thanks?order=10482",
  "cancel_url": "https://store.example.com/cart",
  "expires_at": "2026-09-09T10:30:00Z"
}

Only the issuer of the request may open a session on it, and only while the request is created.


GET /checkout/sessions/{id}

Public.

{
  "id": "cs_4b81f2c7",
  "status": "open",
  "success_url": "https://store.example.com/thanks?order=10482",
  "cancel_url": "https://store.example.com/cart",
  "payer_member": null,
  "attempts": 0,
  "expires_at": "2026-09-09T10:30:00Z",
  "completed_at": null
}

payer_member

The wallet completing the session — and where this stops being theoretical.

Today a checkout completes only inside the wallet its provider chose. Under PATH it may be a wallet at another member entirely, and the merchant integrates nothing extra. That field being populated with a name the merchant has never heard of is the protocol working.


POST /checkout/sessions/{id}/attempt

Called by the payer's wallet when it starts.

{ "payer_member": "member-b" }
{ "id": "cs_4b81f2c7", "attempts": 1 }

Attempts are counted, never overwritten. A payer who tries three wallets before one works is a normal story, and a merchant investigating a complaint needs all three.


Lifecycle

Fig. 01 — Lifecycle
open
completed
expired
cancelled

What is not here, and why

Partial payments, several concurrent attempts against one session, and refunds tied to an order are RESERVED for a later version.

The line that keeps this pillar small: PATH specifies what crosses between the merchant's provider and the payer's wallet. The basket, tax, shipping, inventory, promotion codes and the payment page belong to whoever built the store — which is where products should differ.

If the session later acquires a lifecycle of its own — partial settlement, dispute tied to delivery — that is the signal to reconsider whether the demand deserves richer treatment. It is a decision to take with evidence, not in advance.


Webhooks

DRAFT
EventWhen
checkout.session.completedThe session completed
checkout.session.expiredIt expired unpaid
request.paidThe underlying request was marked paid
receipt.issuedA settlement receipt was issued

Deliveries are signed with the operator's key, same envelope as everything else, so a receiver verifies them the way it verifies anything.

Treat delivery as at-least-once. Duplicates happen; make handlers idempotent on the event id. Re-marking a paid request as paid is deliberately not an error, for exactly this reason.

On this page