agent lost the checkout session after a long 3DS wait: payment abandoned
Keeps a payment alive across long 3DS waits so a customer isn't abandoned mid-checkout. Use when sessions expire during authentication or customers report being dumped back to the cart. Not for 3DS failures themselves or declined cards.
agent lost the checkout session after a long 3DS wait: payment abandoned
TL;DR
Set the checkout session expiry well beyond the worst-case 3DS wait, store the session id against the order server-side, and recover by retrieving the session on return instead of creating a new one. If the session already expired, rebuild it from the stored order with the same idempotency key. Customers should come back to a payment, not a dead link.
agent lost the checkout session after a long 3DS wait: payment abandonedFix it
- Extend the expiry. Set session
expires_at(or the provider equivalent) to at least 24 hours; some 3DS flows with bank apps take 10+ minutes. Success check: a session created in staging is still retrievable after 12 hours. - Persist the session id with the order. Store it in your own database keyed by order id before redirecting. Success check: your order row always has a session id after redirect.
- Recover, don't recreate. On the return URL, retrieve the session by the stored id and read its payment status. Success check: a customer returning after 20 minutes sees their payment state, not a fresh cart.
- Handle the truly-expired case. If retrieval says expired, create a replacement session reusing the same order and idempotency key, then redirect once. Success check: only one paid payment_intent exists for the order.
When this applies
- Customers are dropped to the cart or an error page after completing 3D Secure.
- An agent orchestrates checkout redirects and sessions can outlive a single run.
When it doesn't
- The customer failed or canceled 3DS; that is an authentication outcome, not a session bug.
- The session was created without any redirect flow (embedded elements); check element lifecycle instead.
Compatibility
- Pattern: agent-driven checkout on Stripe Checkout Sessions, Adyen drop-in/redirect, or any hosted session with an expiry.
- Stripe API 2024-06 and later (Checkout Session
expires_atconfigurable).
Variant: customer opened the bank app and the browser tab timed out
The tab died but the session was still valid server-side. Same fix: the return/refresh path retrieves by stored id and resumes.
Variant: agent rebuilt the session and double-created payment intents
Same fix with emphasis on step 4: reuse the idempotency key when recreating so the provider dedupes.
Why it happens
Hosted sessions default to short expiries. An agent that treats the redirect as fire-and-forget loses the handle; when the customer returns after a long authentication, there is nothing valid to return to.
Edge cases
- Some providers cap expiry at a max (e.g. 24h for Stripe Checkout); design the recovery path for that ceiling.
- If the customer completed payment in the dead tab, the retrieve in step 3 may show
paidalready; never create a new session without checking first.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_KsQ1RHXsPXgljFuyOyWZ1Q