Skip to content
Sandbox open: magic test cards, hosted checkout and signed webhooks · 55 payment methods in the catalogue, cards to crypto · Built and hosted in the EEA · Read the API reference at /developers

Sandbox open: magic test cards, hosted checkout and signed webhooks

Documentation

API reference

Checkout sessions

Create a hosted payment page, send the payer to it, and read the result: parameters, the session object, lifecycle and the return URLs.

Updated

A checkout session is a time-limited intent to be paid, plus a page we host to collect the payment. You create the session, send the payer to url, and they come back to your success_url with the payment already made.

This is the shortest integration there is: no card form, no tokenisation, no card data anywhere near your servers. The page runs through the same orchestrator as the API, so a payment made on it is indistinguishable from one you created yourself.

Create a session

POST /v1/checkout-sessions → 201 with a checkout session object.

ParameterRequiredNotes
amountyesPositive integer, minor units.
currencyyesLowercase ISO 4217.
referenceyesYours, 1–64 characters.
success_urlyesAbsolute https URL. Where the payer lands after paying.
cancel_urlnoAbsolute https URL. Where "back" goes.
descriptionno≤ 500 characters. Shown on the page.
capture_methodnoautomatic (default) or manual.
allowed_methodsnoUp to 20 wire method names. Omitted means card only.
customer_emailnoPre-fills the receipt field.
customernoAn existing cus_ id.
allowed_originsnoUp to 10 https origins. Accepted and stored for the embedded mode; v1 is redirect-only.
expires_innoSeconds, 1800 to 604800. Default 86400 (24 hours).
metadatanoSame rules as on a payment.
curl https://cleared-pay.com/api/v1/checkout-sessions \
  -H "Authorization: Bearer $CLEARED_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2000,
    "currency": "eur",
    "reference": "ORDER-10432",
    "description": "Order 10432 — 1200 credits",
    "allowed_methods": ["card", "ideal", "blik"],
    "customer_email": "buyer@example.com",
    "success_url": "https://merchant.example/checkout/done",
    "cancel_url": "https://merchant.example/cart",
    "expires_in": 3600,
    "metadata": { "cart_id": "c_881" }
  }'

The session object

{
  "id": "cs_01JBXQ2M4K7T9V3ZC8HR5N6PWD",
  "object": "checkout_session",
  "status": "open",
  "url": "https://cleared-pay.com/pay/cs_01JBXQ2M4K7T9V3ZC8HR5N6PWD",
  "amount": 2000,
  "currency": "eur",
  "reference": "ORDER-10432",
  "description": "Order 10432 — 1200 credits",
  "capture_method": "automatic",
  "allowed_methods": ["card", "ideal", "blik"],
  "customer_email": "buyer@example.com",
  "customer": null,
  "success_url": "https://merchant.example/checkout/done",
  "cancel_url": "https://merchant.example/cart",
  "payment": null,
  "metadata": { "cart_id": "c_881" },
  "livemode": false,
  "created": "2026-08-19T10:15:00Z",
  "expires_at": "2026-08-19T11:15:00Z",
  "completed_at": null
}
FieldNotes
statusopen, completed or expired.
urlThe hosted page. Send the payer here; the id is the capability, so treat the URL as one.
paymentThe pay_ id once a payment has been attempted. null before that.
completed_atSet when the session completed.

Which methods the page offers

The page shows allowed_methods intersected with what is actually routable for your account, minus wallets — Apple Pay and Google Pay need a real device flow, which the sandbox cannot simulate. With no allowed_methods the page offers card only.

A method you listed that is not enabled on your account simply does not appear. If nothing is left, the session cannot be paid — check your routing before you send a payer.

Lifecycle

  1. open — created, unpaid, within expires_at.
  2. The payer opens url and pays. A declined attempt leaves the session open so they can try another card or another method; that is deliberate.
  3. completed — the payment reached captured, authorized or processing. checkout_session.completed fires.
  4. expired — expires_at passed without a completing payment. checkout_session.expired fires. Expiry is applied lazily on read as well as by a scheduled job, so a read is never stale.

The return

The success redirect appends two parameters to your success_url:

https://merchant.example/checkout/done?session_id=cs_01JBXQ2M4K7T9V3ZC8HR5N6PWD&payment=pay_01JBXQ4N7P2R8T5WY9AC3EF6HK

Do not treat the redirect as proof of payment. A payer can close the tab, lose connectivity, or edit the URL. Fulfil on the checkout_session.completed or payment.captured webhook, and use the redirect only to show the right screen. If you need to render a result immediately, read the session back:

curl https://cleared-pay.com/api/v1/checkout-sessions/cs_01JBXQ2M4K7T9V3ZC8HR5N6PWD \
  -H "Authorization: Bearer $CLEARED_SECRET_KEY"

What the page is

Cleared-pay-controlled, CSP-locked, and script-inventoried for PCI DSS 6.4.3 — the inventory is part of the repository and a test fails the build on any third-party script. Card data entered there is tokenised inside a single server action and discarded; nothing card-shaped is persisted or logged.

The page is redirect-only in v1: it sets frame-ancestors 'none' and cannot be embedded. allowed_origins is accepted now so an embedded mode later needs no change to your integration.

TODO(compliance): a live session renders "Live payments are not enabled yet" until a live connector is in place. Everything on this page works today with a test key.

Testing it

Create a session with a test key, open url, and pay with a number from the magic-card table. 4242 4242 4242 4242 captures, 4000 0000 0000 9995 gives you a soft decline and the retry behaviour, and 4000 0000 0000 3220 sends you through the simulated challenge page.