Skip to content

Events & error handling

The checkout object reports results through two events:

Event DataDescription
checkout_session.succeeded—Payment completed successfully.
payment.failed{ error: { type, message, code? } }Payment failed.
checkout.addEventListener('checkout_session.succeeded', function () { /* … */ });
checkout.addEventListener('payment.failed', function (event) { /* event.error.message */ });
checkout.removeEventListener('payment.failed', handler);
checkout.dispose(); // clean up all listeners

checkout_session.succeeded fires in the customer's browser — it is a convenience signal, not proof of payment. Always confirm the Checkout Session server-side before fulfilling.

Handle interruptions

Scenario What happensWhat to do
Customer closes the app or browser while a payment is in progressIf the request already reached the backend, the transaction continues processing server-side and completes normally — but the result can't be delivered to the closed frontend.Store the Checkout Session id before calling continue(). When the customer returns, call /checkoutsessions/retrieve with it and present the outcome.
Customer clicks Cancel on the checkoutNo payment was initiated.Call checkout.dispose() to clean up listeners and unmount components. No server-side action is needed — an unused Checkout Session expires naturally.
Customer is inactive for an extended periodThe Checkout Session has a server-enforced expiry (expiresAt in the create response). A continue() after expiry is rejected by the backend.Handle the resulting payment.failed event — typically by creating a fresh Checkout Session.
3D Secure authentication failsControl returns to your page via payment.failed, with error.type, error.message, and optionally error.code.The Checkout Session remains active — the customer may retry without a new one.
Customer doesn't complete the wallet confirmation (Apple Pay / Google Pay)The wallet SDK manages its own sheet. Dismissing it initiates no payment and fires no event; the checkout stays mounted.Nothing — the customer can try again. If the Checkout Session has since expired, handle it as the inactivity case above.
Network timeoutTwo sub-cases. (a) Timeout before the Checkout backend receives a processor response: the backend automatically issues a reversal, so the transaction doesn't remain ambiguous. (b) The backend received a processor response but delivery to the frontend was lost.For (b), treat it like a closed browser: on reconnection, call /checkoutsessions/retrieve to determine the outcome.

Next steps