Everything here is general guidance, not professional advice. We research carefully and can still be wrong or out of date, so treat it as suggestions to check rather than instructions to follow, and accept that you act on it at your own risk. Full terms.

BlogCustomers charged twice in Stripe, what to do

Customers charged twice in Stripe, what to do

Stop duplicate Stripe charges, identify the affected payments, refund confirmed duplicates, and repair retries and webhook handling before reopening checkout.

If customers were charged twice in Stripe, pause the affected payment path. Match each reported charge to its Stripe payment record before refunding anything. Keep the intended payment, resolve the confirmed duplicate, and check that retries cannot create another charge.

These steps are for the business collecting the payment. Start the customers charged twice playbook alongside your incident notes. Give one person responsibility for payment decisions and another for investigating the integration, if your team allows it.

1. Stop the path creating duplicates

Pause the checkout, retry worker, or operator action you suspect. Choose the smallest part you can safely disable. Keep existing payment records and logs so you can reconstruct what happened.

Write down when the reports started, the affected checkout version, and recent payment changes. Record whether the duplicates followed a timeout, a customer retry, or a manual action. Treat these as leads until you match them to payment records.

Avoid asking customers to try paying again while you investigate. Have support collect the order number, amount, currency, and approximate time. Keep full card numbers and credentials out of the incident notes.

For an existing PaymentIntent integration, Stripe recommends one PaymentIntent per order or customer session. Reuse it when checkout resumes. A PaymentIntent tracks payment attempts and produces at most one successful charge. Look for multiple PaymentIntents attached to the same intended purchase.

2. Establish what happened to each payment

Build a small reconciliation list. For each affected order, record the Stripe payment IDs, current status, amount, currency, and which payment should remain. Add refund IDs as you resolve them.

Do not decide from matching amounts alone. Two legitimate orders can cost the same. Compare the purchase records and ask the customer which order they intended when the evidence is unclear.

Check whether the apparent duplicate is an uncaptured authorization. Stripe’s authorization and capture guide explains that a hold reserves funds for later capture. That is a different state from a completed payment.

Use the payment’s actual state to choose the next action. An unexplained statement entry needs investigation before you issue a compensating payment. If you cannot match it, give Stripe support the relevant payment IDs and your timeline through your authenticated account.

Keep unknown cases on the list with a named owner. A missing local order is a reason to check Stripe, rather than evidence that money never moved.

3. Refund only the confirmed duplicate

For a completed duplicate, use Stripe’s documented refund flow. Find the payment on the Payments page, open its overflow menu, and choose Refund payment. Check the amount and reason before clicking Refund. The default is a full refund.

Read the payment ID aloud or have a second person check it against your list. Record which valid payment remains. This review matters most when several payments share the same customer and amount.

An uncaptured PaymentIntent with requires_capture needs cancellation instead of a direct refund. Stripe documents that distinction on the same refund page. Refunds return to the original payment method.

Check the resulting refund status. Available balance funds refunds; an insufficient balance can leave card refunds pending. Keep those cases open. If cash availability is part of the problem, use the Stripe payouts frozen playbook to organize the account and cash investigation.

Tell customers the affected amount, what you have done, and the current status. Promise a follow-up you control. Avoid promising a bank posting date.

4. Fix payment retries

Compare the original request with its retries. Did each attempt use a different key? Did a timeout cause your application to create a new payment object?

Stripe’s idempotent request documentation explains how a key lets the API recognize a repeated operation. Keep the same key for retries of the same operation, with the same parameters. Generate a separate key for a genuinely new operation.

For API v1, Stripe returns the saved result for the key after execution begins, including saved server errors. Replacing the key after an ambiguous error can therefore bypass the protection you needed.

Keep your own durable order-to-payment mapping too. Stripe can prune API v1 keys after at least 24 hours. Reusing a pruned key can create a new request. An old retry still needs an application check against the intended purchase.

Have the integration owner test a timeout and a repeated checkout submission in a sandbox. Require one intended purchase to map to one successful payment before restoring that path.

5. Check webhook handling separately

A webhook is a notification sent to your application. Two notifications need not mean two charges. Stripe can deliver an event more than once and does not guarantee event order.

Record processed event IDs and skip repeat processing. Stripe also describes duplicates represented by separate Event objects; check the underlying object ID together with the event type. Review any handler that creates payment operations or fulfillment work.

Test duplicate and out-of-order delivery against the repaired handler. Check both the payment records and customer access. A successful HTTP response alone says little about whether you shipped twice or granted duplicate credit.

If delivery failures left orders out of sync, continue with the payment webhooks failing playbook. Reconcile the missed window before replaying events in bulk.

6. Reopen with an accountable checklist

Before reopening, review every affected order. Each should have a documented payment outcome and an owner for any unresolved refund. Check the order, invoice, fulfillment, and customer access records against that outcome.

Keep support informed about pending cases so another operator does not refund the retained payment. Monitor new orders for the original duplicate pattern as traffic returns.

Open Prepare and complete the duplicate-charge safeguards. Store order-to-payment mappings, assign refund permissions, and schedule a retry drill with the person who will handle the next payment incident.