How to Prevent Double Billing During SaaS Exits

Last updated:

Double billing is the most visible and damaging mistake you can make during a subscription migration. When customers see two charges for the same service, trust erodes immediately. This guide covers the strategies and safeguards to prevent it.

How Double Billing Happens

Double billing occurs when both the old and new subscriptions charge the customer for the same billing period. Common causes:

Scenario 1: Premature New Subscription

You create the new subscription before canceling the old one, and both hit their billing dates.

Timeline:

  • Day 1: Old subscription bills customer
  • Day 5: You create new subscription (bills immediately or on anchor)
  • Day 15: Old subscription bills again (wasn’t canceled)

Scenario 2: Wrong Proration Settings

You create the new subscription without disabling proration, causing an immediate prorated charge.

Scenario 3: Race Condition

You cancel the old subscription and create the new one, but the old subscription’s invoice had already been finalized.

Scenario 4: Timezone Confusion

The billing anchor is set incorrectly due to timezone differences, causing the new subscription to bill at the wrong time.

Prevention Strategy 1: Atomic Migration

The safest approach is to treat the migration as an atomic operation:

  1. Read the old subscription’s current state
  2. Create the new subscription with matching billing anchor
  3. Verify the new subscription is active
  4. Cancel the old subscription only after verification

Never reverse this order. Never cancel the old subscription without confirming the new one exists.

Prevention Strategy 2: Billing Anchor Alignment

When creating the new subscription, set the billing anchor to match the original:

// Read original anchor
const originalAnchor = oldSubscription.billing_cycle_anchor;

// Create new subscription with same anchor
await stripe.subscriptions.create({
  customer: newCustomerId,
  items: [{ price: newPriceId }],
  billing_cycle_anchor: originalAnchor,
  proration_behavior: 'none'
});

The proration_behavior: 'none' is critical. Without it, Stripe may charge immediately for a prorated period.

Prevention Strategy 3: Idempotent Execution

Design your migration to be safely re-runnable:

  • Before creating a subscription, check if one already exists for that customer
  • Track which subscriptions have been migrated in your database
  • Use idempotency keys for Stripe API calls

If a migration fails partway, you can safely re-run without creating duplicates.

Prevention Strategy 4: Deferred Cancellation

Instead of immediate cancellation, consider canceling at period end:

await stripe.subscriptions.update(oldSubscriptionId, {
  cancel_at_period_end: true
});

This ensures the old subscription doesn’t renew but doesn’t immediately stop service. However, this approach requires careful timing to avoid overlap billing.

Prevention Strategy 5: Invoice Draft Review

Before finalizing the new subscription, review any draft invoices:

const invoices = await stripe.invoices.list({
  subscription: newSubscriptionId,
  status: 'draft'
});

// Review invoice amount and date before finalizing

This lets you catch unexpected charges before they hit the customer.

What MoveMRR Does

MoveMRR implements all these safeguards automatically:

  1. Validates state before action: Confirms old subscription status before proceeding
  2. Sets correct billing anchors: Preserves original renewal dates
  3. Disables proration: Prevents immediate prorated charges
  4. Verifies before canceling: Only deactivates old subscriptions after confirming new ones
  5. Logs everything: Complete audit trail for troubleshooting
  6. Idempotent design: Safe to re-run without duplicates

Recovery If Double Billing Occurs

If double billing happens despite precautions:

  1. Refund immediately: Issue a full refund for the duplicate charge
  2. Communicate proactively: Don’t wait for customers to complain
  3. Document the incident: Record what happened for process improvement
  4. Review the audit log: Understand the sequence of events

Pre-Migration Checklist

Before executing any migration:

  • Confirmed billing anchor dates for all subscriptions
  • Verified API keys have correct permissions
  • Tested with a small subset first
  • Have refund process ready if needed
  • Customer communication drafted