Knowledge

Stripe Double Charges When Moving Subscriptions

Why customers get charged twice when subscriptions move to a new Stripe account, how to prevent it, and what to do if a double charge already happened.

· Simon Liang

A Stripe double charge happens when the old and the new Stripe account both bill the same customer for the same period. Three settings prevent it: start the new subscription schedule at the old subscription's current_period_end, hold anything renewing within 48 hours, and set cancel_at_period_end on the old subscription only after the new schedules are verified. If it has already happened, refund the duplicate from the account that charged it (section 5).

For the full migration steps, read the full runbook. If you are transferring the whole account instead (only possible within the same legal entity), that is simpler.

How a double charge happens

Stripe's Customer Data Copy moves customer records and saved payment methods between accounts. It does not move products, prices, billing meters, subscriptions, or subscription schedules. The destination account starts with cards and zero subscriptions.

The typical mistake:

  1. The operator sees the copied customers in the destination account.
  2. The operator creates an active subscription for each customer.
  3. Stripe charges each card at once.
  4. The source subscription is still active and already charged the same customer for this period.

The customer pays twice for the same period.

Two other paths lead to the same result. A subscription renews in the source account during the move, current_period_end rolls forward, but a schedule built from the old date charges the customer again right after. Or the old subscriptions are never cancelled after the new ones go live. Stripe's Billing migration toolkit documentation warns: "cancel old subscriptions before they charge so you don't double-bill."

Five ways to prevent a Stripe double charge

1. Start each schedule on the renewal date

Never create an immediate subscription in the destination account. Create a subscription schedule with a future start date:

  1. Read the source subscription with a read-only restricted key.
  2. Take its current_period_end.
  3. Create a destination schedule that starts on that exact timestamp.
  4. Attach the recreated price and the copied customer.

The destination account waits until the paid period ends, then sends the regular renewal invoice. Unlike a subscription created directly, the first invoice of a schedule with charge_automatically starts as a draft. Stripe finalizes it about an hour later. One charge, on the expected date.

2. Flag renewals within 48 hours

A subscription that renews during the migration can collide with it. The source account charges the renewal, current_period_end moves forward, and a schedule built from the old date charges the customer again right after.

Flag every subscription that renews within 48 hours. Let it renew in the source account first. After current_period_end rolls forward, move it after it renews in the source account.

3. Check the default payment method

Stripe's customer copy sometimes drops the invoice default payment method. A customer with a saved card but no default fails to pay when the schedule starts, and the invoice goes past due.

Verify every copied customer in the destination account. Where the default is missing, set it from the copied payment method before any schedule is created.

4. Cancel at period end, never immediately

There are two ways to cancel a Stripe subscription. Cancelling immediately is Stripe's default: the subscription ends and no further invoices are generated. Cancelling at period end (cancel_at_period_end: true) keeps the subscription active through the paid period and stops only the next renewal.

Never cancel the source subscriptions immediately. That ends paid access before the destination schedule starts. Set cancel_at_period_end: true. The source subscription stays active until the period ends and sends no further invoice. At that moment the destination schedule starts.

cancel_at_period_end can be undone until the period ends: update it to false to reactivate the subscription. That safety margin is why it is the right default.

5. Three gates, three keys

  1. Read-only source. The source key can only read. Catalog recreation, customer verification, and schedule creation all run while the source account keeps billing.
  2. Decisions on flagged subscriptions. Subscriptions renewing within 48 hours, with discounts or coupons, existing schedules, manual tax rates, a missing default payment method, legacy metered prices, and customers sharing an email each get a decision from the source owner. Invoice-billed subscriptions and trialing subscriptions are set up by hand. Past-due subscriptions are fixed first.
  3. Verify, then add a narrow cancellation key. Read each schedule back from Stripe and compare it with the source subscription. Only then add a separate key with read plus subscription write access, just enough to set cancel_at_period_end.

What the customer sees

With these five settings in place, the customer pays once, on the date the charge was already due, from the new account. The destination subscription schedule starts at current_period_end, so there is no double charge and no free days. The old subscription ends at period end with no further invoice. The customer's next statement looks the same as every other renewal.

Already charged twice? How to fix it

If a customer was already billed by both accounts for the same period, fix it in this order:

  1. Find both payments. Open the source account and the destination account. Look for two charges to the same customer for the same period.
  2. Refund the duplicate. Decide which account keeps the customer (normally the destination). In the account that took the extra payment, issue a full refund on that charge. Refunds go to the original payment method only. Your customer sees the refund as a credit in about 5 to 10 business days, depending on the bank. A refund issued soon after the charge can appear as a reversal instead. The original charge drops off the customer's statement, and a separate credit is not issued.
  3. Check the refunding account's balance. Refunds come from the available Stripe balance, not pending amounts. A new destination account may not have enough yet. Card refunds in that case wait as pending until the balance is sufficient.
  4. Stop it from happening again for that customer. If the source subscription is still active, set it to cancel_at_period_end. If a destination subscription started too early, fix it through its schedule. Cancelling a schedule cancels the subscription. Releasing a schedule leaves the subscription in place but removes the schedule and any remaining phases.
  5. Do not refund if the customer already opened a dispute. Stripe recommends accepting or challenging the dispute instead, to avoid reimbursing the customer twice.
  6. Tell the customer what happened and when the refund lands. Customer messages are your job.

What stays your job

These mechanisms cover Stripe Billing objects only. Your team still updates the application database with the new IDs, switches the API keys, points the webhooks at the destination account, and checks entitlements.

Doing it with SubPorter

The five mechanisms run as gates in a migration project. The source account stays read-only until every schedule is verified, with three restricted keys. Renewals within 48 hours are flagged. The cancel step opens only after the schedules are verified: the source owner adds a key with read plus subscription write access, ticks the confirmation, and clicks "Cancel source at period end." That step cannot be undone in the room.

$99 for up to 100 subscriptions, $199 above 100. One-time, not based on MRR.

Scan your source account for free to see what needs to move, or view pricing.

Frequently Asked Questions

Why does moving subscriptions to a new Stripe account cause double billing?

Stripe’s customer copy moves customers and cards, not subscriptions. If an operator creates active subscriptions in the destination account while the source subscriptions still run, both accounts charge the same customer for the same period.

How do subscription schedules prevent a double charge?

A subscription schedule has a start date. Set it to the source subscription’s current_period_end, and the destination account bills only after the paid period ends.

Why hold subscriptions that renew within 48 hours?

A renewal during the migration moves the period end forward, and a schedule built from the old date can charge the customer again. Let these subscriptions renew in the source account first, then move them after they renew.

Should source subscriptions ever be cancelled immediately?

No. Set them to cancel at period end. The customer keeps paid access until the destination schedule starts at that same moment. Cancelling at period end can be undone until the period ends; cancelling immediately cannot.

How does SubPorter verify the schedules before the cancel step?

SubPorter reads the schedules back from Stripe, and the source subscriptions can be set to cancel at period end only after the schedules are verified.

A customer was charged twice after the move. What do I do?

Find the duplicate payment in the account that charged it and issue a full refund. Refunds go to the original payment method and take about 5 to 10 business days. If the customer already opened a dispute, do not also refund.