Skip to content
Back to blog

Occurly August 12, 2026 2 min read

How to migrate a billing system without missing a cycle

Billing migrations fail on cutover, not on data. A staged approach that keeps invoices going out on time.

A software team working at a bank of monitors
migration 2 min

Billing migrations have an unusual property: the system you are replacing cannot be switched off for a weekend, because customers are mid-cycle and invoices are due. That constraint shapes everything.

The good news is that the data is rarely the hard part. Plans, customers, subscriptions and historical invoices are structured and exportable. The hard part is cutover.

Migrate the catalogue first, and simplify while you do

Your existing plan catalogue almost certainly contains plans nobody has been sold in two years, three variants of the same plan that differ only by a discount, and at least one plan that exists because of a single customer.

Migrating that faithfully preserves a mess. Take the opportunity to collapse it: map old plans to a smaller set, and keep the mapping. The mapping is what you will need later when someone asks why a customer’s plan name changed.

Run both systems in parallel for at least one full cycle

Parallel running is the step teams try to skip and the step that catches everything. Both systems compute the same period. Nobody is billed twice, because only the incumbent actually sends.

Then compare, invoice by invoice. You are looking for differences in proration, rounding, tax treatment and discount ordering. Every one of those will differ slightly, and every one is easier to reconcile now than after cutover.

Expect a handful of genuine differences where the new system is right and the old one was quietly wrong. Those need a decision, not a patch.

Cut over by cohort, not all at once

There is rarely a reason to move every customer on the same day. Moving in cohorts lets you contain a problem to a fraction of the book.

A sensible order is: internal accounts, then a small set of simple monthly subscriptions, then annual contracts, then anything with usage, multi-entity or custom terms. Complexity last, when you have already found the ordinary bugs.

Decide what happens to history

You have three options and they are all defensible:

  • Leave history in the old system and keep it readable. Cheapest, but you now have two places to look.
  • Import invoices as records without recomputing them. Preserves what the customer was actually charged, which is what matters in a dispute.
  • Recompute history in the new system. Almost never worth it, and it will not match, because tax rules and rates change over time.

The middle option is right for most teams. What was charged is a historical fact, not something to be recalculated.

The cutover checklist

Before the first live cycle on the new system:

  • Payment methods are tokenised and verified, not just copied
  • Webhooks are pointed at the new system and the old ones are disabled
  • The dunning sequence is configured, and it does not immediately retry historical failures inherited from the migration
  • Someone owns the first close, and has time blocked for it

That last one is the most commonly missed. The first close on a new system takes longer, and planning for it to take a normal amount of time is how a good migration becomes a stressful one.