{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition","cards","card"]},"type":"markdown"},"seo":{"title":"Events & error handling","description":"Shift4 Payment Platform REST API."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"events--error-handling","__idx":0},"children":["Events & error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The checkout object reports results through two events:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"width":"300px","data-label":"Event"},"children":["Event "]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Data"},"children":["Data"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkout_session.succeeded"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["—"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Payment completed successfully."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payment.failed"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{ error: { type, message, code? } }"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Payment failed."]}]}]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"js","header":{"controls":{"copy":{}}},"source":"checkout.addEventListener('checkout_session.succeeded', function () { /* … */ });\ncheckout.addEventListener('payment.failed', function (event) { /* event.error.message */ });\ncheckout.removeEventListener('payment.failed', handler);\ncheckout.dispose(); // clean up all listeners\n","lang":"js"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkout_session.succeeded"]}," fires in the customer's browser — it is a convenience signal, not proof of payment. Always ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/core-concepts/checkout/confirm-payment"},"children":["confirm the Checkout Session server-side"]}," before fulfilling."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"handle-interruptions","__idx":1},"children":["Handle interruptions"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"width":"240px","data-label":"Scenario"},"children":["Scenario "]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What happens"},"children":["What happens"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What to do"},"children":["What to do"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Customer closes the app or browser while a payment is in progress"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["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."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Store the Checkout Session ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]}," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["before"]}," calling ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["continue()"]},". When the customer returns, call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/checkoutsessions/retrieve"]}," with it and present the outcome."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Customer clicks Cancel on the checkout"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No payment was initiated."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkout.dispose()"]}," to clean up listeners and unmount components. No server-side action is needed — an unused Checkout Session expires naturally."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Customer is inactive for an extended period"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The Checkout Session has a server-enforced expiry (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["expiresAt"]}," in the create response). A ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["continue()"]}," after expiry is rejected by the backend."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Handle the resulting ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payment.failed"]}," event — typically by creating a fresh Checkout Session."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3D Secure authentication fails"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Control returns to your page via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payment.failed"]},", with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.type"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]},", and optionally ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code"]},"."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The Checkout Session remains ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["active"]}," — the customer may retry without a new one."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Customer doesn't complete the wallet confirmation (Apple Pay / Google Pay)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The wallet SDK manages its own sheet. Dismissing it initiates no payment and fires no event; the checkout stays mounted."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Nothing — the customer can try again. If the Checkout Session has since expired, handle it as the inactivity case above."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Network timeout"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["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."]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["For (b), treat it like a closed browser: on reconnection, call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/checkoutsessions/retrieve"]}," to determine the outcome."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"next-steps","__idx":2},"children":["Next steps"]},{"$$mdtype":"Tag","name":"Cards","attributes":{"columns":3,"cardMinWidth":240},"children":[{"$$mdtype":"Tag","name":"Card","attributes":{"title":"Confirm the payment","imagePosition":"start","iconPosition":"auto","layout":"vertical","align":"start","variant":"filled","to":"/guides/core-concepts/checkout/confirm-payment"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Retrieve the Checkout Session server-side — the source of truth for fulfilment."]}]},{"$$mdtype":"Tag","name":"Card","attributes":{"title":"Test cards","imagePosition":"start","iconPosition":"auto","layout":"vertical","align":"start","variant":"filled","to":"/guides/core-concepts/checkout/testing"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Sandbox card numbers for success, failure, and 3D Secure scenarios."]}]}]}]},"headings":[{"value":"Events & error handling","id":"events--error-handling","depth":1},{"value":"Handle interruptions","id":"handle-interruptions","depth":2},{"value":"Next steps","id":"next-steps","depth":2}],"frontmatter":{"title":"Events & error handling","description":"The Payment components event model — checkout_session.succeeded and payment.failed — plus dispose(), and how to handle interruptions like closed browsers, expiry, and 3DS failures.","markdown":{"lastUpdatedBlock":{"hide":true}},"seo":{"title":"Events & error handling"}},"lastModified":"2026-10-08T08:30:07.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/core-concepts/checkout/payment-components/events-and-errors","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}