The checkout object reports results through two events:
| Event | Data | Description |
|---|---|---|
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 listenerscheckout_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.
| Scenario | What happens | What to do |
|---|---|---|
| Customer closes the app or browser while a payment is in progress | If 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 checkout | No 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 period | The 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 fails | Control 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 timeout | Two 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. |