Skip to main content
The checkout runs in an iframe and talks to your page over postMessage. The SDK turns that into callbacks.
Never fulfil an order from a browser callback.These fire in the customer’s browser. If they close the tab, lose signal, or their battery dies, the callback never runs — but the payment still completed. Use webhooks for fulfilment and these for UI.

The callbacks

function
The checkout iframe has loaded and finished its handshake with your page. Good moment to hide your own loading state.It does not mean on-chain verification has run. That check happens later, inside the checkout, once the customer is paying — and if it fails, the customer sees a blocking “configuration mismatch” screen. Your page is not told either way.
function
The payment completed. Fires once. Receives the payment payload: { txHash, rail, merchantId, chainId, token, amount, currency, orderId, intentId, v }.orderId is the reference you passed to updateCart (null if you passed none); intentId is ours, and the same id the webhook carries. v is the payload version, currently 2 — the keys from version 1 are all still there.It does not fire at the moment the payment became irreversible. When the customer pays from a connected wallet their money is already final once their own transaction confirms, but this callback — and the success screen they are looking at — waits for our settlement step afterwards, so a slow settlement leaves them on a spinner and delays your thank-you redirect. Nothing is at risk while they wait; the money can only reach your pool. Coming The success screen and this callback move to the moment of finality. Roadmap.Use it to redirect to a thank-you page or show a success state — not to release goods.
function
A payment attempt failed. Receives { orderId, intentId, reason, retryable, … }. It is not called when a customer simply declines in their wallet — they can still pay.When retryable is true, the customer can still complete the same order in the same checkout — don’t cancel it.
function
The price lock lapsed before funds arrived. Receives { orderId, intentId, lateSettlementWatched, watchUntil, … }.When lateSettlementWatched is true, the pay-to address is still being watched until watchUntil, and a payment that arrives late completes this order — onPaymentConfirmed can still follow. Don’t cancel the order until the watch is over.
function
The checkout closed. Receives { reason, orderId, intentId }: reason is completed when the customer pressed Done after paying, dismissed otherwise. A customer can pay and then close, so don’t read dismissed as abandonment on its own.

Typical usage

The race you need to handle

A customer can pay and immediately close the tab. Your webhook fires; your onPaymentConfirmed doesn’t. Design your thank-you page to read order state from your server, not from the callback. Then a customer who closes early and comes back still sees the right thing.

Checkout states

The customer may see these. Worth recognising them in support conversations. If the checkout can’t start a payment at all — including when a customer has hit a rate limit — it shows “We couldn’t start this payment.” with a Try again button. There is no countdown and no automatic retry. A customer paying with a connected wallet may also see an optional “Sign this message” prompt from the wallet before paying. It isn’t required — dismissing it leaves them connected and able to pay. Removing that stray prompt is a known improvement that has not shipped yet.

Set up webhooks

The reliable path. Do this before going live.