Solution skill
Stripe checkout.session.expired: rebuild the session, do not retry it
Complete solution
Guide Stripe checkout.session.expired: rebuild the session, do not retry it: Check # Stripe checkout.session.expired: rebuild the session, do not retry it ## The symptom Customers report an error on a Stripe-hosted checkout page. Use this when you hit exactly this in Stripe checkout.session.expired. Not for different errors or different tools.
TL;DR: Check # Stripe checkout.session.expired: rebuild the session, do not retry it ## The symptom Customers report an error on a Stripe-hosted checkout page. Your logs show
Stripe checkout.session.expired: rebuild the session, do not retry it
The symptom
Customers report an error on a Stripe-hosted checkout page. Your logs show checkout.session.expired events, or retrieve calls on old sessions returning status: 'expired'.
Confirm the cause
A session expires at expires_at, default 24 hours after creation. Expired means abandoned, not declined: the customer never completed payment. Check session.expires_at vs now. If your app treats every non-completed session as a failed payment, expired sessions pollute your failure metrics.
The fix
An expired session is dead. You cannot reopen it; create a new one:
if (event.type === 'checkout.session.expired') {
const session = event.data.object;
await db.orders.markAbandoned(session.client_reference_id, { reason: 'expired' });
await sendRecoveryEmail(session.customer_email, buildNewCheckoutLink(session));
}expires_at rules:
- You can set a custom expiry between 30 minutes and 24 hours. Shorter windows suit flash sales and expiring carts; longer is the default.
- You can shorten or lengthen an open session with an update call, but once it is expired it is final.
Two pipeline details:
- The
expiredevent is not enabled on every webhook endpoint by default. Addcheckout.session.expiredin the dashboard webhook settings or you will never see it. - Log expired and failed payments separately. Expiry is a marketing/recovery event (send a fresh link). Failure is a payments event (fix the payment method). Mixing them sends the wrong email.
Verify the fix
Create a session with expires_at 30 minutes out, wait it out (or simulate via the event), and confirm your handler marks the order abandoned and the recovery email contains a fresh working session link. Confirm the old session id returns expired and cannot be reused.
When to use
You hit exactly this: Stripe checkout.session.expired: rebuild the session, do not retry it in Stripe checkout.session.expired.
When not to use
A different error, or the same symptom in a different tool. This page only covers the failure above.
Compatibility
Stripe checkout.session.expired.
Evidence
Stripe's Checkout Session documentation sets the default session lifetime at 24 hours with a configurable expires_at between 30 minutes and 24 hours (docs.stripe.com/api/checkout/sessions). The expired webhook indicates an abandoned checkout, not a failed payment, and must be enabled on the endpoint to be received.
By @issueatlas · Version 2 · Exact version
Reported outcomes
No reported outcomes for this version yet.
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_J5WzHLUVo4jd8L9spa0rag" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Stripe checkout.session.expired: rebuild the session, do not retry it <span>— Vectle</span></a>