Skip to content

Stripe Checkout errorStripe: “This Checkout Session has expired”

A Stripe Checkout Session lasts 24 hours by default, and after that the customer sees a message that it has expired and can’t pay. The usual cause is a checkout link created ahead of time and opened later, such as one saved in an email, a database or a page that was left open.

Short answer

Create a new Checkout Session each time the customer clicks to pay, and redirect to its URL straight away instead of storing or emailing that URL. Set expires_at if you need a shorter window. To win back customers whose session ran out, enable after_expiration.recovery and listen for the checkout.session.expired webhook.

Rather not fix it yourself? Stripe Billing Fix and Setup handles it at a fixed price, agreed before work starts.

Why the session expired, and the fix

  1. 01

    The session URL was created too early

    “It can be anywhere from 30 minutes to 24 hours after Checkout Session creation. By default, this value is 24 hours from creation.” Stripe, Create a Checkout Session (expires_at)

    A session made when a page loads, or saved and sent later in an email, can be past its time when the customer finally clicks. Create the session on the server when the customer clicks Pay, and redirect right away. The snippet assumes a form POST; if you call it with fetch(), return session.url as JSON and set window.location in the browser.

    app.post('/checkout', async (req, res) => {
      const session = await stripe.checkout.sessions.create({
        mode: 'payment',
        line_items: [{ price: 'price_123', quantity: 1 }],
        success_url: 'https://example.com/success',
      });
      res.redirect(303, session.url);
    });
  2. 02

    Your code expired it

    “After it expires, a customer can’t complete a Checkout Session and customers loading the Checkout Session see a message saying the Checkout Session is expired.” Stripe, Expire a Checkout Session

    Calling the expire endpoint ends a session at once. Some apps expire an open session when the cart changes or the customer leaves; if the customer goes back to the old tab, that session is gone. Send them through a fresh session.

  3. 03

    Bring the customer back with a recovery link

    “When the customer opens this URL, it creates a new Checkout Session that’s a copy of the original expired session.” Stripe, Recover abandoned carts

    Enable after_expiration.recovery when you create the session. When it expires, the checkout.session.expired webhook carries a recovery URL you can put in a follow-up email. Stripe’s recovery flow also needs consent_collection.promotions set to auto and the customer’s consent to promotional email.

  4. 04

    Clean up when a session expires

    “Listen to the checkout.session.expired webhook to be notified when customers abandon Checkout and sessions expire.” Stripe, Recover abandoned carts

    If you reserved stock or held a seat for the order, release it when the session expires, so items aren’t stuck in carts that will never pay.

Checked against the vendor’s docs on : Stripe API: Create a Checkout Session (expires_at); Stripe API: Expire a Checkout Session; Stripe docs: Recover abandoned carts.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

“Working with Simon makes everything run so smoothly and better than I could ask for it. Amazingly communicative, extremely knowledgeable of coding and the backend processes. I strongly recommend.”
A buyer in the United States, January 2026. App development on Fiverr
All 127 Fiverr reviews

Related: Stripe “No such checkout.session” · Stripe paid but account not upgraded · Stripe webhook signature verification failed · Stripe expired_card

Questions

More on this error

Can I make a session last longer than 24 hours?

No. Stripe allows expires_at from 30 minutes to 24 hours after creation. For a link that has to stay valid for days, use a Payment Link or create the session when the customer clicks.

How long does the recovery link work?

Stripe says the recovery URL is usable for 30 days, shown by after_expiration.recovery.expires_at in the webhook payload.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.