# Stripe: charge_expired_for_capture

> Stripe returns charge_expired_for_capture when a held payment is captured after the authorization expired. Charge again, then capture before capture_before.

Canonical: https://app369.com/fix/stripe-charge-expired-for-capture/
Last updated: 2026-11-09

charge_expired_for_capture is the Stripe error for capturing a held payment after its authorization ran out. Online card holds usually last 7 days; after that the funds go back to the customer and the payment is canceled.

**Short answer**

The held money is gone, so ask the customer to pay again, or charge a saved payment method with a new PaymentIntent if the customer agreed to that. Then fix the timing: store capture_before for each authorized charge and capture before it, or request an extended authorization when creating the PaymentIntent, where the card is eligible.

Rather not fix it yourself? [**Stripe Billing Fix and Setup**](https://app369.com/fixed-price/stripe-billing-setup/) handles it at a fixed price, agreed before work starts.

## **Why the capture fails, and the fix**

1. 01 ### **The order shipped after the hold expired**
  > “The charge can’t be captured because the authorization has expired.” [**Stripe, Error codes (charge_expired_for_capture)**](https://docs.stripe.com/error-codes) A store that captures on shipping fails for orders that wait more than about a week. Capture when the order is ready, or charge in full at checkout for slow orders.
2. 02 ### **The app assumes 7 days for every payment**
  > “You need to capture the funds before the authorization expires.” [**Stripe, Place a hold on a payment method**](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method) Windows differ by card network, payment method and in-person versus online. Read capture_before on the charge and schedule the capture from that date.```
const pi = await stripe.paymentIntents.retrieve(id, { expand: ['latest_charge'] });
const captureBefore = pi.latest_charge.payment_method_details.card.capture_before;
// schedule the capture to run before captureBefore (Unix seconds)
await stripe.paymentIntents.capture(id);
```
3. 03 ### **Bookings need a longer hold**
  > “Usually, an authorization for an online card payment is valid for 7 days.” [**Stripe, Place a hold on a payment method (extended authorizations)**](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method) Hotels, rentals and similar bookings can ask for an extended authorization on eligible online card payments, so the hold lasts past the usual window.
4. 04 ### **The capture job didn’t run** Also check: a failed cron or queue can leave held payments to expire. Alert on PaymentIntents in requires_capture that are close to capture_before.

Checked against the vendor’s docs on November 9, 2026: [Stripe docs: Error codes](https://docs.stripe.com/error-codes); [Stripe docs: Place a hold on a payment method](https://docs.stripe.com/payments/place-a-hold-on-a-payment-method).

## **Rather hand it over?**

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

- [$950**Stripe Billing Fix and Setup**Subscriptions, webhooks, customer portal and failed payments set up or fixed, tested in Stripe test mode.**See scope and start**](https://app369.com/fixed-price/stripe-billing-setup/)
- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****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.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

[**All 127 Fiverr reviews**](https://app369.com/reviews/)

Related: [**Stripe charge_already_refunded**](https://app369.com/fix/stripe-charge-already-refunded/) · [**Stripe PaymentIntent authentication failure**](https://app369.com/fix/stripe-payment-intent-authentication-failure/) · [**Stripe coupon_expired**](https://app369.com/fix/stripe-coupon-expired/) · [**Stripe Checkout Session expired**](https://app369.com/fix/stripe-checkout-session-expired/)

Questions

## **More on this error**

<details>

<summary>**Was the customer charged? **+</summary>

No. The hold is released when the authorization expires, so nothing was collected and nothing needs a refund. A pending hold may still show on the statement for a few days.

</details>

<details>

<summary>**Is there a related error code? **+</summary>

Yes. Stripe also lists capture_charge_authorization_expired for an expired authorization, and a PaymentIntent that already shows canceled may return payment_intent_unexpected_state instead. Handle them the same way: the hold is gone, so charge again.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

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.

</details>

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.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)