Migrate from another billing system
Migrations are achievable — typically over a 2-week window — if you sequence them right. The Paylera import API accepts customer, payment-method, and subscription records with their existing IDs preserved, so foreign keys in your application keep working.
The shape of a migration
day -14 discovery: count customers, plans, payment methods, currenciesday -10 set up live tenant; recreate catalog (codes match)day -7 dual-write payment-method tokens to both systemsday -3 dry-run import against sandbox; verify totalsday 0 cutover window: import customers + active subs; flip API base URLday +7 reconcile invoices and ledger against source-of-truth reportday +14 shut down old system; archive its dataResist the urge to compress. The ledger reconciliation at day +7 is where pain hides.
1. Discovery
You need a list of:
- Active customers and their email + foreign keys.
- Active subscriptions with plan, billing anchor, current period start / end, trial end, commitment status.
- Payment methods on file (token + last 4 + brand + expiry).
- Outstanding invoices in
open,partially_paid,past_due. - In-flight refunds and chargebacks.
If any of those numbers can’t be exact, they will come back to bite you in reconciliation.
2. Recreate the catalog
The plan codes you import must exist in the live tenant before the import. Use Build a catalog — same shape as your previous system, code-matched so subscriptions land on the right plan.
For pricing changes (you’re moving systems anyway, why not) — keep the old catalog also present with the original codes, and let grandfathered customers stay on it.
3. Migrate payment method tokens
This is the only step that can’t be done after cutover. Card tokens are
provider-specific (a Stripe pm_… is meaningless to Paylera unless
your live tenant uses the same Stripe account).
Two paths:
-
Same provider, same account: your provider gives you a way to reference existing tokens against a new “platform” or PaymentIntent flow. Paylera’s import accepts the existing token directly:
POST /v1/admin/import/payment-methods{"items": [{ "customer_id": "cus_…", "type": "card", "external_token": "pm_old_…", "last4": "4242", "brand": "visa", "exp": "12/27" },…]} -
Different provider or same provider, different account: you must re-collect cards. The standard pattern is to send “update your payment method” emails 2 weeks before cutover with a hosted-checkout setup-mode session. Customers who don’t migrate end up in dunning after cutover; that’s recoverable but noisy.
4. Import customers and subscriptions
POST /v1/admin/import/customers{ "items": [ … ] }Each customer record can include external_ids: { stripe: "cus_old…", your_app: "u_28471" } — Paylera persists these and they’re searchable
via GET /v1/customers?external_id=….
POST /v1/admin/import/subscriptions{ "items": [ { "customer_id": "cus_…", "plan_code": "pro-monthly-usd", "status": "active", "current_period_start": "2026-04-15T00:00:00Z", "current_period_end": "2026-05-15T00:00:00Z", "billing_cycle_anchor": "2026-04-15T00:00:00Z", "trial_end": null, "default_payment_method_id": "pm_…", "metadata": { "external_id": "sub_old_…" } }, … ]}Imports are upserts by metadata.external_id when present — you can re-run safely. Imported subscriptions don’t trigger an immediate invoice; the next billing cycle proceeds as scheduled.
5. Cutover
The cutover is two changes:
- Your application starts calling Paylera (new base URL, new key) for subscription / invoice / payment operations.
- Your provider’s webhooks point at the Paylera ingress, not the old billing system.
Webhooks during the cutover window are tricky — both systems may receive duplicates. Configure both to be idempotent on your handler.
6. Reconciliation
A week after cutover, run the same totals against both systems and make them match:
- Active subscription count by plan code.
- MRR by currency.
- Open AR balance.
- Recognised revenue for the cutover month.
The GET /v1/reports/* endpoints make these queryable. If anything
doesn’t match, the most likely causes are:
- A subscription on the old system that was missed in the import.
- A subscription whose
current_period_endwas off by a day (timezone bugs). - Refunds in flight at cutover that one system saw and the other didn’t.
Fix in Paylera (operator-driven adjustments are audited). Don’t try to edit the old system after cutover.
7. Shutdown
Once reconciled, shut down the old billing system’s webhook delivery and revoke its API keys. Keep its data archived for the longer of:
- Your retention policy (typically 7 years for billing records).
- Any open dispute / chargeback windows (180 days for cards).
Common pitfalls
- Lost trial end dates. Preserve
trial_endexactly. A customer who thinks they have 5 days left and gets billed instead is a refund + a churn signal. - Lost commitment terms. If the old system tracked commitments, re-import them or you’ll let customers cancel mid-commitment.
- Mid-period plan changes. A subscription that just upgraded before cutover may have a proration credit pending on its next invoice. Carry the credit by importing it as a wallet balance.
- Affiliate attribution. Re-import attributions explicitly via
POST /v1/admin/import/affiliations— don’t trust your CRM to be authoritative.
Get help
Migrations of more than ~5,000 active subscriptions warrant a
conversation. Email migrations@paylera.io and we’ll loop in someone
who’s done your source system before.