Stripe checkout session expiration: how long customers have to pay

Online checkout screen with payment details and shopping cart

The newsletter for newsletter operators

Daily field notes on deliverability, AI tools, hosting, and monetisation. No "top 10 plugins" filler — real tools, real numbers, real failures.

Stripe checkout session expiration: how long customers have to pay
Photo by Ze Vieira on Unsplash

If you’re selling digital products, courses, or subscriptions through Stripe, you’ve probably sent customers to a checkout session URL. What you might not know is that those URLs don’t last forever—and the default expiration window catches more operators off guard than it should.

Stripe checkout sessions expire 24 hours after creation by default. If a customer clicks your payment link on Monday afternoon but doesn’t complete the purchase until Wednesday, they’ll see an error page. No purchase, no conversion, and you’ll never know they tried unless you’re watching session analytics closely.

What checkout session expiration actually controls

When you create a Stripe checkout session—either via API or through a payment link—Stripe generates a unique URL tied to that session ID. The expiration timer starts immediately, whether the customer has opened the link yet or not.

The expires_at parameter defaults to 24 hours from creation. You can extend it to a maximum of 90 days by passing a Unix timestamp when you create the session:

expires_at: Math.floor(Date.now() / 1000) + (7 * 24 * 60 * 60)

That example sets expiration to seven days out. If you’re sending payment links via email, SMS, or embedding them in automated workflows, seven days is a safer window than one.

Once a session expires, Stripe won’t accept payment through that URL. The customer sees a generic “This payment link is no longer valid” message. There’s no automatic redirect, no retry logic, and no way to extend the session retroactively. You’ll need to generate a new checkout session and send a fresh link.

When short expiration windows backfire

The 24-hour default makes sense if you’re generating checkout links dynamically at the moment a customer clicks “Buy Now” on your site. But it breaks down in three common scenarios:

Email campaigns. If you’re sending a product launch email to 5,000 subscribers with an embedded checkout link, some will open that email three days later. The link is already dead. You’ll see click activity in your email analytics but zero corresponding Stripe sessions.

Abandoned cart recovery. You send a reminder email 48 hours after someone adds a product to their cart. The original checkout session you generated is expired. The recovery email drives traffic to a broken link.

Multi-step onboarding flows. A new user signs up, receives a welcome email with a payment link, then takes four days to complete onboarding and decide to subscribe. Expired. You’ve lost the conversion unless you trigger a new session programmatically when they return.

How to set expiration based on your funnel

If you’re generating checkout sessions via Stripe’s API, pass expires_at explicitly. Here’s the decision tree most operators settle on:

  • Same-session purchases (customer clicks Buy Now and checks out immediately): 24 hours is fine.
  • Email or SMS payment links: 7 days minimum. Some operators go 14.
  • Evergreen product pages or affiliate links: 30–90 days if you’re generating static links and don’t want to refresh them manually.

If you’re using Stripe Payment Links (the no-code option in the Dashboard), you don’t control expiration—they’re permanent by default unless you manually deactivate them. That’s actually an advantage if you’re embedding links in automated emails or posting them publicly.

The trade-off: Payment Links don’t support advanced session parameters like custom metadata per checkout or dynamic tax calculation. If you need that, you’ll need to generate sessions via API and manage expiration yourself.

One non-obvious detail: expired sessions still appear in your Dashboard

Even after a session expires, Stripe keeps the record visible in your Dashboard under Payments → Checkout Sessions. The status reads expired, but you can still see when it was created, what product was attached, and whether the customer opened the link (Stripe tracks that via a checkout.session.viewed webhook event).

If you’re debugging conversion drop-off, filter your sessions by status: expired and compare the count to status: complete. A high expired-to-complete ratio often means your expiration window is too short for your funnel velocity.

One more thing: expired sessions do not trigger a webhook. If you’re relying on webhooks to update user records or send follow-up emails, you won’t get notified when a session times out. You’ll need to poll session status via the API or set up a scheduled job to catch stale sessions before they expire.

Want more operator-level breakdowns of tools, workflows, and pricing details? Subscribe to One Two Three Send—every article unpacks one specific mechanism that online-business operators actually need to understand.

The newsletter for newsletter operators

Daily field notes on deliverability, AI tools, hosting, and monetisation. No "top 10 plugins" filler — real tools, real numbers, real failures.

Other newsletters you might like

Love Spain

Love Spain — in your inbox. Iconic cities, hidden pueblos and the best places to visit in Spain. One short email, every day.

Subscribe

My Local Dublin

The Dublin you don't see from a tour bus — local stories, hidden gems, food, events and the best of the city, by locals for locals.

Subscribe

Springbokfans

The best Springbok updates, straight to your inbox. Only when something worth reading actually happens.

Subscribe

Irish Rugby Fans

The best Irish rugby updates, straight to your inbox — Six Nations, the Nations Championship and the provinces. Only when there's something worth reading.

Subscribe

Newsletters via the One Two Three Send network.  ·  Want your newsletter featured here? Click here