genv.

MigrationMigrating from WHMCS without losing invoice history

15 min readPublished Reviewed By the GENV team

In short

Move customers, services and domains as live records, and bring invoices — open ones included — payments and credits across as historical evidence rather than as records your new system will act on. Plan the balances still owed separately, with exactly one system entitled to collect each. Reconcile by totals per customer per year before you switch, and keep the old system readable for as long as your record-keeping obligations require.

WHMCS migrations go wrong in a predictable place. The live data — customers, products, services — moves reasonably well, because it describes the present. The financial history does not, because it describes decisions made under rules that no longer exist: tax rates that changed, a product that was renamed, a credit applied by somebody who has left. And it is the part you cannot reconstruct if you get it wrong.

Decide what is live and what is evidence

What is live, what is evidence, and what needs a plan
DataCategoryWhy
Customers and contactsLiveYou will act on these tomorrow
Services and domainsLiveThey renew, suspend and get supported
Open invoicesEvidenceThe document is history, like a paid one. It is not how the balance gets collected
Outstanding balancesCutover planCollected by exactly one system, decided per balance and reconciled at the switch
Paid invoicesEvidenceImmutable history. Do not let a new system recalculate them
Payments and refundsEvidenceSame. The totals must not move
Support ticketsEvidenceRead, searched, occasionally reopened
Product definitionsRebuildCopying old products imports old mistakes

The distinction matters because a new system will happily recalculate a historical invoice against its own tax rules and produce a different number. A paid invoice from 2023 is a statement of what happened. It should be stored, displayed and never recomputed.

Outstanding balances are a cutover decision, not an import

An open invoice is two things at once: a document, which is history, and a balance, which somebody still owes. Import the document as evidence. Plan the balance on its own:

  1. Decide, for each outstanding balance, which system collects it — the one you are leaving, until it is settled, or the new one, as a charge raised there deliberately. Record the decision.
  2. At the switch, reconcile the outstanding total on both sides: what the old system says is owed must equal what your plan accounts for, balance by balance.
  3. Move billing authority for each customer at one recorded moment. Renewals falling due before it are invoiced by the old system and those after it by the new one, so nothing is billed twice and nothing falls into a gap where neither bills.

Stopping the old system invoicing some time before the switch does not remove the risk; it moves it. Whatever falls due in between is billed by nobody, unless the plan says who.

Reconcile before you switch, not after

Pick totals that are cheap to compute on both sides and compare them:

  • Count of customers, and count of active services.
  • Sum of issued invoice totals per year.
  • Sum of payments received per year.
  • Count of open invoices and the sum outstanding.
  • Count of domains, and the number expiring in the next ninety days.

Any difference is a finding, not a rounding error. Chase each one to a cause before you go further — likely causes include deleted-but-referenced records, multi-currency totals summed as one number, and credit notes counted as invoices.

The order of operations

  1. Export from WHMCS while it is still live. Keep the raw export unmodified — it is what you re-import from and reconcile against — and protect it as the copy of your customers' personal data that it is: restricted access, encrypted at rest, kept for as long as your legal, tax and contractual obligations require, and deleted under a documented policy once they no longer do.
  2. Import into a staging copy of the new system and reconcile the totals above.
  3. Fix the importer, not the data. A hand-edited import cannot be repeated, and you will need to repeat it.
  4. Rebuild products and prices by hand in the new system. This is the moment to drop the bespoke arrangements.
  5. Re-run the import into the real system, freshly, from the same raw export.
  6. Reconcile again, then switch the customer-facing surfaces.
  7. Once billing authority has moved, stop WHMCS raising anything new — its jobs off, apart from whatever your plan says it still collects — and keep it readable for as long as your record-keeping obligations require.

Step three is the discipline that makes the rest work. Every manual fix during a migration is a difference between staging and production that nobody will remember on the day.

What not to bring

  • Stored card details. These belong to a payment processor, not to your database, and moving them between systems is a compliance question with an expensive wrong answer. Re-collect the mandate.
  • Old product definitions. Rebuild them. You know more now than when you wrote them.
  • Staff accounts for people who have left. A migration is a free opportunity to clean the access list.
  • Automation settings. Turn everything off, migrate, then turn each thing on deliberately while watching it.

Provisioning continuity

The services exist on real servers, and those servers do not know you are migrating. The new system must be able to recognise an existing hosting account as belonging to a customer without creating a new one — and it must not do that by matching a username, which is a guess. Require evidence, or require a person to confirm it explicitly, one account at a time.

Where GENV is

GENV has a migration workbench that imports customers, services, domains, financial history and support threads, with a mapping step, a preflight that checks a manifest and imports nothing, and a reconciliation view that compares what arrived with what was claimed.

GENV imports invoice history as evidence that collects nothing. Every imported invoice — paid or open — lands in its own tables and stays there. None becomes a GENV invoice, and the invoice number series counts only what the workspace has itself issued; the importer cannot write into it, which the schema enforces and a migration test checks. An imported open invoice cannot enter a customer's balance, an ageing report, a payment reminder or a renewal. So an outstanding balance needs the plan above: GENV keeps the record of what your old system said was owed, and who collects it is a decision you make and reconcile outside the import. The WHMCS documentation is at docs.whmcs.com.

Questions

How long should the old system stay available?

Long enough to answer questions about the last closed accounting period, and for as long as the tax and record-keeping rules where you trade require those records to stay available. Read-only is enough.

Can I migrate in stages?

Customers and services, yes — by server or by product. Financial history can be staged too, provided every period ends up with one consolidated, reconciled record: each invoice and payment counted once, in one place, with totals that agree with the source. What to avoid is a year split across two systems with nobody reconciling the halves.

What about open invoices at the moment of the switch?

Treat the invoice and the balance separately. The invoice is history: import it as a record of what the old system said, and in GENV it stays exactly that — it cannot be collected, age or trigger a reminder. The balance needs its own plan: decide which system collects each one, reconcile the outstanding total on both sides at the switch, and move billing authority at one recorded moment so that only one system is ever entitled to bill a customer for a given period. That avoids both double billing and a gap in which nobody bills.

Sources

  1. WHMCS — documentation

Official documentation, each requested on 21 September 2026. Provider behaviour changes; check the source before relying on a detail.