Skip to content

Docs / Merchant guide

Importing subscribers

Migrate from any subscription app: a confirmed column mapping, a read-only readiness report, preserved prices and addresses, and a billing hold for a safe cutover.

The importer moves your existing subscribers into WallaB.AI™ from a CSV export — from any subscription app. You confirm how your file's columns map to WallaB's fields, review a full read-only dry run, and only then commit. Not a single subscription is created until you do.

Any app's export works

WallaB no longer needs a hand-built adapter for the platform you're leaving. Whatever app it is, you upload its CSV export and confirm a column mapping — which of your file's columns holds the email, the price, the billing cadence, and so on. WallaB proposes that mapping automatically from your file's headers, and you confirm it against a live preview of your own parsed rows before anything runs. That per-import confirmation is the guarantee, so no vendor is "unsupported".

Pick your source on the Import page:

  • Generic CSV template (recommended) and Recharge have verified column layouts. They import as before — the mapping step is prefilled and optional, so a clean template or a Recharge export just works.
  • Appstle, Skio, and Loop are offered as presets. Appstle prefills a best-effort mapping from its known export shape; Skio and Loop auto-detect from your file's headers. All three ask you to confirm the mapping against your real file before the batch can validate or commit — an honest per-file check, not a promise that a format we've never seen will line up.
  • Any other app — use the generic template, or upload the app's own export and map its columns. The mapping step handles the rest.

Limits: files up to 10 MB and 5,000 rows per batch. Larger migrations split cleanly into several files — each is deduplicated against the others, so there is no penalty for splitting.

Confirm the column mapping

After you upload, WallaB reads your file's header row and proposes a mapping — matching each column to a WallaB field by exact name first, then by a known synonym, then by a close fuzzy match. Anything it can't place is left for you to map by hand from a dropdown of your file's columns.

AI-assisted suggestions. When gaps remain, WallaB can ask its AI to propose fills for the unmapped fields. It only ever sees your column headers and a type signature for each column (for example "looks like an email", "integer", "date") — never your customers' actual values. Names, emails, addresses, and phone numbers are redacted before anything leaves your store. Each AI-proposed field carries an "AI-suggested" badge, and — like every other field — you confirm it yourself. The importer works fully without an AI key configured: the automatic header-based proposal always serves, and the AI layer is a bonus on top of it.

The date format is never guessed. A date like 03/04/2026 is genuinely ambiguous — it could be March 4th or April 3rd. When your next-charge dates are written that way, WallaB stops and asks you to choose month-first or day-first; it never assumes one. (An unambiguous date — 2026-08-01, or one whose day is past the 12th — is detected without asking.) This matters because the next-charge date decides exactly when a customer is billed.

European money formats are handled. 1.234,56 and 1,234.56 both import as 1234.56. A value whose grouping is genuinely ambiguous — for example 125.000, which could mean 125000 or 125.0 — is not guessed; it becomes a visible row error for you to fix, never a silent 1000× misread of a price.

You review the proposed mapping against a preview of your own rows — parsed exactly as they'll import — and adjust anything before continuing.

The generic CSV column reference

Prefer to start clean? Download the template (the Download our template link on the Import page) — a ready-to-fill file with the exact header row and one example row. Save it as UTF-8; a leading byte-order mark (BOM) is tolerated. Columns are matched by name, not position, so extra columns you don't need are ignored rather than shifting the mapping.

One CSV row is one subscription (one product line). Every column the generic template understands:

ColumnRequired?TypeFormat & constraintsExample
customer_emailRequiredstringThe subscriber's email, name@example.com shape, up to 320 characters. Matched case-insensitively; an existing customer is reused, never duplicated.shopper@example.com
customer_first_nameOptionalstringFree text. Used only if the customer is new to your store.Jane
customer_last_nameOptionalstringFree text. Used only if the customer is new to your store.Doe
product_titleRequiredstringMust match an ACTIVE product in your WallaB.AI catalog — paired with variant_title, or matched by variant_sku when that is supplied.Colombian Dark Roast
variant_titleOptionalstringCombined with product_title for the catalog match. Omit if you match by variant_sku.12oz Bag
variant_skuOptionalstringIf present, matched case-insensitively against your catalog SKU and takes precedence over the title pair — the most reliable way to map a row.COFFEE-DARK-12
quantityRequiredintegerA positive whole number, 1 to 999.1
unit_priceRequireddecimalA non-negative number using a dot decimal separator (no currency symbol or thousands separators). Rounded to 2 decimal places.18.00
currencyOptionalstringA 3-letter ISO 4217 code. Leave it blank to use your store's own currency — that is the right choice for almost every migration. When supplied it is used verbatim, so it must be a currency your Shopify store is set up to charge in; a non-blank value that is not a 3-letter code is a row error.USD
interval_unitRequiredenumOne of day, week, or month (case-insensitive). Together with interval_count this is the billing cadence.month
interval_countRequiredintegerA positive whole number — e.g. 2 with interval_unit=week bills every two weeks.1
next_charge_dateRequireddateA calendar date, ISO 8601 (YYYY-MM-DD) recommended. Required for active and paused rows; optional for cancelled rows. A past date imports the row PAUSED — it is never charged for time already served.2026-08-01
statusRequiredenumOne of active, paused, or cancelled (case-insensitive). A cancelled row imports as history for win-back, not an active subscription.active
source_subscription_idOptionalstringYour source platform's stable subscription id. When present it is the dedup key; when blank, a fingerprint of the email, cadence, and line is used instead. Either way a re-import never creates a duplicate.sub_10432

Deduplication

Each row carries a natural key: its source_subscription_id when you provide one, otherwise a fingerprint of the customer email, cadence, and line. At most one subscription is ever created per key — enforced by the database, not just app logic — so re-importing the same export changes nothing: matching rows are flagged and skipped, never duplicated and never used to overwrite the subscription that already exists. To edit an already-imported subscription, use the subscriber's page rather than re-uploading.

The migration readiness report

Before you commit, WallaB runs a read-only dry run — the migration readiness report — that shows exactly what will happen. It writes nothing: no subscriptions, no charges, no emails, no changes in Shopify. It only simulates, and you can refresh it as often as you like.

For the staged batch, the report tells you:

  • What will import — how many rows import cleanly, how many import with a warning worth a look, how many were already imported in an earlier batch and will be skipped, and how many will fail (with the top reasons grouped).
  • Plan coverage — every billing cadence in your file and whether a selling plan is ready for it. An unmapped or drifted cadence is a blocker: nothing commits until it's resolved, and the report says so plainly.
  • Prices — how many subscribers keep a grandfathered price lower than your current catalog price, the per-cycle total those preserved prices bill once billing starts, and how many will be priced from your catalog instead.
  • Addresses — how many rows bring a valid delivery address, how many had an address that was dropped as invalid, and how many carry none.
  • Payment methods (live stores) — how many subscribers already have a saved payment method that will bill, and how many don't yet. This live check is bounded at 200 customers per run; beyond that, the report is honest that the remainder are unverified rather than silently assuming them.

Map each cadence to a plan

Every billing cadence in your file maps to one of your selling plans. Where an eligible plan already bills that exact cadence, pick it. Where none does, use the in-flow Create plan button: WallaB creates a pricing-neutral plan for that exact cadence on the spot — no discount, no pricing tiers — so it can carry your imported prices unchanged. Tiered plans are excluded from import mapping (their charge is recomputed at billing time, which would override a preserved price); Create plan is the path for any cadence a tiered plan would otherwise cover.

Your subscribers keep their prices

An imported subscriber is billed the exact price from your export, verbatim — not your current catalog price. That is how a grandfathered rate survives the migration.

  • A row with a price keeps it as that subscriber's ongoing per-unit price.
  • A row with a blank price is priced from your current catalog (times any plan discount) instead.
  • A $0 price imports as a comped (free) subscription — kept, but flagged with a warning so a free import is never silent.
  • A negative or unparseable price is a row error, never a guess.

Delivery addresses come along

If your export carries ship-to address columns, they import with the subscriber. An address is an enhancement, never a gate:

  • A complete, valid address is attached to the imported subscription.
  • A partial or invalid address is dropped with a row warning — the subscription still imports without it, and you can add the address later from the subscriber's page.
  • A missing country is never guessed. WallaB won't infer it from your store's market, because a wrong country on a shipping label is worse than none — so the address is dropped with a clear reason for you to correct.

Switching from another billing app

If these subscribers are still active in your old subscription app, you don't want both apps charging the same customer during the cutover. On the commit step, check "hold billing … until I confirm it's switched off". WallaB then creates every subscription but charges no one — they're held.

Once you've switched the old app off, come back and click Start billing to release the hold; WallaB then bills each subscription on its existing schedule. That is what keeps a migrated shopper from being billed twice. Leave the box unchecked for a fresh import that isn't moving off another billing app.

Payment methods themselves don't migrate in the CSV — they follow later via Shopify's contract transfer.

Validate, then commit

Nothing touches your live data until you commit. Every row is staged and gets a verdict — valid (ready), warning (importable, worth a look), or error (won't import, with the exact reason). Once the readiness report is clean and each cadence is mapped, committing is owner-only and asks you to type the count of subscriptions being created to confirm. Committing enqueues the rows for processing, and the batch report shows exactly what happened to each.

Safety guarantees

  • No welcome emails. Imported subscribers never receive new-signup onboarding messages — nobody gets "welcomed" to a service they've been using for a year.
  • No billing for time already served. A row whose next charge date is already in the past imports as paused, never as an overdue charge.
  • No double imports. Each source subscription key is remembered; re-uploading the same export cannot create duplicates.

The migration dashboard

Once a migration is underway, Migrate Subscribers → Migration dashboard tracks it end to end, one batch at a time. It's read-only — nothing on it changes your data — and it answers the four questions a cutover actually raises:

  • Where is this migration? The five steps — uploaded, columns and plans mapped, reviewed in a dry run, subscriptions created, billing released — each with what happened or what's waiting on you. A migration that wasn't a cutover from another app shows the last step as "not needed" rather than leaving you with a bar that never finishes.
  • What landed? Imported, warnings, skipped and failed counts. Rows rejected at validation are counted separately from rows the commit tried and couldn't create — they're different problems.
  • Is anyone being billed yet? How many subscriptions are still held versus released. If a batch has sat on hold for three days or more, the dashboard asks whether you're still waiting on your old app's switch-off and links straight to the release step. It's a reminder, not a deadline: nothing expires, and WallaB never releases a hold for you.
  • Who can't be billed? A migrated subscription can only be charged if the customer already has a card saved in Shopify. The dashboard lists the subscribers who don't — either no saved card, or no linked Shopify customer — with their emails partly hidden. Those subscribers need to add a payment method from their portal; WallaB never touches card data.

After the cutover it also reconciles: where the imported subscriptions ended up (active, paused, cancelled), and whether any subscription's first charge after you released the hold failed, with its dunning state. A later failure is ordinary churn and doesn't appear here — this list exists so a migration problem is never mistaken for one.

Want us to run it? White-glove migration

On the Pro plan and above you can ask our team to run the migration with you: we map your columns, sort out the cadences, walk the cutover, and stay on the thread until the first charges land. Use Request white-glove migration at the bottom of the migration dashboard. It opens a normal support ticket on your plan's usual response time, pre-filled with the batch number, the source platform and the row counts — no customer details are attached. If you already have an open request for that batch, the button takes you back to it instead of opening a second one. White-glove is capacity-limited — first come, first served.

Everything else stays available on every plan, Free included: the importer, the billing-hold cutover, the readiness report, and this dashboard. Nothing about self-serve migration is gated behind asking for help.

Migration incentive

Completing a migration batch earns you a one-time reward on your WallaB.AI plan — honored as a one-time credit on your WallaB.AI subscription, arranged through Shopify billing by our support team (see Billing plans & support).

Taking your book back out — no lock-in

The door swings both ways. Your subscriber data is always yours, and getting it out is one click: Settings → Your data — no lock-in → Download subscriber book (CSV). There's no support ticket, no waiting period, and no fee.

The file you get back uses the exact same columns as the template above, so it re-imports anywhere — into another subscription app, into your own systems, or straight back into WallaB.AI. We test that round trip: an exported book, re-uploaded here, validates with zero row errors.

What's in the file. One row per subscription line — customer email and name, product and variant, SKU, quantity, the subscriber's current price, currency, billing cadence, next charge date, and status. A subscription with several products exports as several rows, exactly as the importer expects them.

Every subscription is included, not just the live ones: active, paused, and cancelled subscribers all export, so your churn history travels with you and stays available to win-back campaigns wherever it lands. Terminal states (expired, failed) export as cancelled, because that is the honest reading — and it guarantees a lapsed subscriber can never re-import as a live billing subscription.

What the export can't carry (and why)

The portable format is deliberately the importer's format, and that format describes a subscription's billing shape — not every feature layered on top of it. So a few things don't fit in the CSV. We'd rather name them than let you find out later:

  • Delivery addresses. The portable column set has no address columns, so ship-to addresses stay in WallaB.AI. (The importer can read addresses from a file that has them — see "Delivery addresses come along" above — but the round-trip template doesn't emit them.)
  • Payment methods. Card data never lives in WallaB.AI at all, so there is nothing to export. Payment methods move between apps through Shopify's own contract transfer, never a spreadsheet.
  • Prepaid term details. A prepaid subscription exports its delivery cadence and price; the number of cycles already paid for and the batch size are not columns in the format, so a re-import treats it as pay-as-you-go.
  • Build-a-box bundle structure. A bundle's contents export as ordinary line rows — every product, quantity, and price is there — but the fact that they were assembled as one box, and which slot each filled, is not.
  • Discounts, plan configuration, and history. Selling-plan definitions, discount rules, concierge conversations, save-offer history, and billing records aren't in the subscriber book. The price you see per row is the subscriber's current per-unit price, with any grandfathered rate already baked in — so re-importing preserves what each person actually pays.

No subscriber is ever silently left out. Every subscription in your account appears in the file; the list above is about columns the format lacks, not rows it drops.

Two practical notes: the export is owner-only (staff accounts can't download it), and every download is recorded in your account's event log — the count and who asked, never the contents.