Migrating from Recharge.

You can do this yourself, without waiting on anyone. But a Recharge export will not import into Daima as downloaded — Daima reads column names literally, and Recharge splits the data you need across four separate files that you have to join yourself. That reshaping is the real work, and most of this page is about it. Budget an afternoon for a few hundred subscribers, and longer if you have prepaid plans, bundles or ongoing discounts. If you'd rather not, [email protected] will still do it for you.

Read this before you start: do not uninstall Recharge first. Shopify cancels any subscription contract owned by an app 48 hours after that app is uninstalled. Uninstalling to "clean up" starts a countdown you cannot stop, on subscriptions you can no longer manage. Migrate first, cancel the old subscriptions deliberately, and uninstall last.

Why a migration is needed at all

Shopify ties every subscription contract to the app that created it. An app can only read and manage its own contracts — there is no permission that grants access to another app's. Shopify does this deliberately, to stop two subscription apps billing the same customer twice.

The practical consequence: while your subscribers live in Recharge, Daima cannot see them. They won't appear in your Daima dashboard, they aren't counted in its analytics or revenue, and those customers will see nothing in Daima's customer portal. Migrating re-creates each contract under Daima so it can manage them.

Daima does not auto-detect or read your Recharge subscriptions, and there is no button that does this for you. You move the data across in a CSV. There is no setup fee and no migration fee for doing so.

Payment methods are vaulted against the customer, not the app, so Daima reuses the card already on file and your customers don't re-enter anything. Where there's no usable payment method on the Shopify customer record, the contract still imports and activates — Daima flags it, and billing won't succeed until that customer adds one. In practice that's PayPal and wallet-only subscribers, who you'll need to email and ask to re-subscribe.

Daima counts these for you rather than listing them: a flagged contract drops out of the imported list along with the ones that activated cleanly, and what you get instead is a warning banner reading “N activated contracts awaiting a payment method”, plus a line in the batch toast saying how many needed one. A scattered few is the case above. A count that matches everyone you just activated is a permissions problem on Daima's side rather than anything to do with your customers' cards — see troubleshooting before you cancel anything.

Before you start — what doesn't come across

Decide this before you export anything, because two of these are reasons not to use this flow at all. Daima's importer reads 25 columns. If something isn't one of them, it does not migrate.

  • Prepaid subscriptions. The import has a single cadence governing both billing and delivery, so "one charge, three deliveries" cannot be expressed at all. Don't migrate prepaid customers with this CSV flow — email us instead.
  • Discounts. There is no discount column. Whatever you put in line_current_price is what the customer pays from now on, so any ongoing discount has to be baked into that number by you, per line, by hand.
  • Bundles. Daima's import has no concept of a bundle. Each variant becomes an ordinary line item on the contract.
  • Local pickup and any non-shipping delivery. delivery_method_type is accepted but never used; every activated contract is created as a shipped contract with an address.
  • Selling plan IDs. Only the plan name is carried through. Imported contracts are not attached to a Daima plan by the import itself — check your plans match what those customers signed up for.
  • Charge history, cancellation reasons, subscription properties, store credit, gift metadata, loyalty state. None of these have a column. They stay in Recharge, so export them for your own records before you cancel. Recharge retains your data for two years after cancellation and restores it if you reinstall on the same storefront, but subscriptions do not start reprocessing on their own — treat that as a records safety net, not a rollback plan.
  • Payment tokens. Nothing in any CSV makes a customer billable on a new platform. Recharge's Payment Methods - All export does hand you what it holds — processor_name, processor_payment_method_token, processor_customer_token and payment_type — but those tokens are scoped to your processor and to Recharge, so no other app can bill against them. Pull that export anyway: it is the quickest way to see which subscribers are on a payment method held outside Shopify before you cut over.

Daima also has no in-app column mapper and no import preview. The import screen points at "documentation for the full list of supported columns" — step 2 below is that list, and the header row there is the template.

Talk to us before you cancel anything. If any of these apply to your subscribers — prepaid, bundles, ongoing discounts, anything you can't see a column for — email [email protected] before you cancel anything in Recharge. It is far cheaper to decide those cases before cutover than to unpick them after, and it is the difference between most botched migrations and most uneventful ones.

Step 1 — Export from Recharge

Recharge's export is self-serve. In the Recharge merchant portal, open Tools & apps and select Exports, then Create export, pick the export type from the dropdown, tick the columns you want under Select your columns, and run it. Recharge's two help pages label that last button differently — Create export on one, Export data on the other — so take whichever yours shows. Recharge emails a secure link to the address you log in with.

One export is not enough. Recharge splits the data you need across separate files, and the subscriptions export references customers and addresses by ID only — it contains no street address. At minimum you need four, named here exactly as they appear in Recharge's export-type dropdown:

  • Subscriptions - Active (or Subscriptions - All) — the products, quantities, prices and billing frequency, plus the Shopify product and variant IDs.
  • Customers — the only export that carries external_customer_id, the Shopify customer ID that belongs in customer_id. Join it to the subscriptions file on Recharge's own customer_id. Skip this export and you have no Shopify customer ID at all, which drops every row onto the email fallback described in step 2.
  • Customers - shipping addresses — the actual street address, keyed by the address_id that appears on each subscription row.
  • Charges - queued — where the next charge date lives, in a column called scheduled_at. It is not in the subscriptions export. If you skip this file you will not know when anyone bills next, and Daima will silently schedule those customers for tomorrow.

You then have to join them yourself, in a spreadsheet, on the address and customer IDs. Recharge's documentation suggests VLOOKUP, COUNTIF or INDEX + MATCH to match the customer IDs across exports. Plan on doing the join yourself.

Freeze the data before you export. Because these are several files pulled at slightly different moments, they can disagree with each other — a customer who reschedules between the first export and the third ends up with two versions of the truth. Turn off the customer portal options that let subscribers reschedule themselves while you work, and do the exports back to back. Keep the downloaded files: the download button on Recharge's Exports page stops working after 2 hours, though the link Recharge emails you stays valid indefinitely — so don't delete that email until the migration is confirmed.

Step 2 — Reshape it to Daima's columns

This is the part that catches people out. Daima matches column headers literally. There is no aliasing, no fuzzy matching, no column-mapping screen and no preview — the header text in your file has to be exactly the name Daima looks for, in lowercase, with underscores. Headers are case-sensitive: Handle is not handle. Surrounding whitespace is trimmed off, so a space either side of a name is harmless.

Worse, only one column produces an error when it's missing. Every other misnamed column is silently ignored and falls back to a default: status becomes ACTIVE, cadence becomes monthly, currency becomes USD, price becomes 0.00, quantity becomes 1. A file that imports "successfully" can still be wrong in every column but one.

So: build a new sheet with Daima's headers, and fill it from your Recharge files. Here is the full header row, ready to paste into the first line of a new sheet. Everything except handle is optional, but omitting a column means accepting its default:

handle,customer_id,customer_email,upcoming_billing_date,cadence_interval,cadence_interval_count,status,currency_code,delivery_price,delivery_address_first_name,delivery_address_last_name,delivery_address_company,delivery_address_address1,delivery_address_address2,delivery_address_city,delivery_address_province_code,delivery_address_zip,delivery_address_country_code,delivery_address_phone,delivery_method_type,line_variant_id,line_quantity,line_current_price,line_selling_plan_name,line_selling_plan_id

Which Recharge column goes where

Recharge documents the columns in every export and they are stable, so this mapping holds. If you ticked extra columns your header row will have more than this — but these are the ones that matter.

From Subscriptions - Active:

  • address_id → handle
  • customer_email → customer_email
  • external_variant_id → line_variant_id
  • quantity → line_quantity
  • recurring_price → line_current_price
  • order_interval_unit → cadence_interval
  • charge_interval_frequency → cadence_interval_count
  • status → status
  • presentment_currency → currency_code

From Customers: external_customer_id → customer_id. Not the subscriptions file's customer_id, which is Recharge's own internal ID and will not resolve in Shopify.

From Charges - queued: scheduled_at → upcoming_billing_date.

From Customers - shipping addresses: shipping_first_name, shipping_last_name, address_1, address_2, city, zip, company and phone → the matching delivery_address_* columns.

Two need converting rather than copying. Recharge's country and province may hold full names, and Daima translates neither: it uppercases the country code but does not convert it, so United States is sent to Shopify as UNITED STATES and rejected, and the province code is passed through exactly as typed. Convert both to the codes Shopify expects — US and CA — before you import.

The one column Daima requires

  • handle — a unique identifier for the contract. It is the grouping key, the upsert key, and what identifies the row in the list. Any non-empty string works. Rows with a blank handle are skipped without comment. The list renders it as # plus the trailing digits when the handle ends in a number (recharge-1234 appears as #1234), and # plus the whole handle when it doesn't — so prefer a handle that ends in the ID you want to recognise.

Customer

  • customer_id — the Shopify customer ID. Non-digits are stripped, so a full gid://shopify/Customer/… also works. Use this wherever you have it.
  • customer_email — a fallback, used only when customer_id is empty or doesn't resolve.

At least one of these has to resolve to a customer that already exists in Shopify. Daima never creates customers during an import. Prefer customer_id: the email fallback takes the first customer Shopify's search returns, so on a store with duplicate or guest records it can attach a contract to the wrong person, and nothing about the import will look wrong afterwards. In Recharge's exports the customer ID on a subscription row is Recharge's own internal ID, not Shopify's — the Shopify one is external_customer_id in the customers export.

Schedule

  • upcoming_billing_date — the next charge date. Note the name: it is not next_billing_date. Use YYYY-MM-DD.
  • cadence_interval — one of DAY, WEEK, MONTH, YEAR. Daima uppercases this, so a lowercase month from Recharge is fine. Monthly, 1 month and 30 days are not — they import without complaint, then fail at activation with Contract create returned no draft, because Shopify accepts only those four values. Nothing is created and nobody is billed until you fix the value and re-import that handle.
  • cadence_interval_count — a whole number. "Every 4 weeks" is WEEK with a count of 4. Defaults to 1.
  • status — ACTIVE or PAUSED. Defaults to ACTIVE. Nothing else can be activated, and a PAUSED row is created in Shopify as a paused contract.
  • currency_code — uppercase ISO code, e.g. USD. Defaults to USD. Daima trims this one but does not uppercase it, so a lowercase usd reaches Shopify exactly as you typed it. Pass it uppercase.

Recharge keeps the delivery frequency and the charge frequency in two separate columns. Daima has one cadence, used for both billing and delivery. If those two numbers differ on a subscription, that is a prepaid arrangement and it cannot be represented here — see what doesn't come across.

Delivery and address

  • delivery_price — shipping charged per cycle, as a plain number. Defaults to 0. $19.99 is read as 0 and 19,99 is read as 19, so strip currency symbols and use a dot for the decimal.
  • delivery_address_address1, delivery_address_city, delivery_address_country_code — all three are required for activation. The country code must be the two-letter code Shopify expects (US), not the country name.
  • delivery_address_first_name, delivery_address_last_name — these also become the customer's name in Daima. There is no customer_first_name column; if you supply one it is ignored and the customer shows as "Unknown".
  • delivery_address_address2, delivery_address_province_code, delivery_address_zip, delivery_address_company, delivery_address_phone — optional. The province code is passed through untouched, so use the code Shopify expects (CA, not California).
  • delivery_method_type — accepted, stored, and never used. Every activated contract is created as a shipped contract.

These are flat columns, one per field. A delivery_address column containing JSON is silently discarded.

Line items — one row per product

  • line_variant_id — the Shopify variant ID. Required for activation. A full gid://shopify/ProductVariant/… works. In Recharge's export this is external_variant_id; Recharge's own subscription ID is not it, and a product ID will import fine and then be rejected by Shopify at activation.
  • line_quantity — defaults to 1.
  • line_current_price — the per-unit price you want charged, as a plain number. Defaults to 0.00. Recharge's subscriptions export has two price columns and they are not interchangeable: recurring_price is the price per unit, and price is that same figure already multiplied by quantity. Map recurring_price across, not price — putting price into this column on a quantity-of-2 subscription doubles every charge from now on. Either way, this is the price the customer pays going forward, so check it against what they are actually paying today.
  • line_selling_plan_name — optional. Used as the row's title in Daima and passed to Shopify when present.
  • line_selling_plan_id — accepted, stored, and never used.

Anything else in the file is ignored entirely. Extra columns do no harm; they just do nothing.

How multi-product subscriptions group

A contract with several products is several rows sharing one handle. This matters when you choose what to put in the handle column, because Recharge represents a multi-product box the same way — one row per product, all sharing the address (or "purchase") ID, each with its own subscription ID. Use Recharge's address_id as the handle and a four-product box arrives as one contract with four lines. Use the per-product subscription ID and the same box arrives as four separate contracts, billing four times.

The trade-off is real and you should check it: grouping on address ID merges everything shipping to that address, so a customer who genuinely has two unrelated subscriptions on different cadences at one address ends up with them fused. Which matters because of the next rule.

The first row of a handle wins every contract-level field. Status, cadence, billing date, currency, customer and address are all read from the first row Daima sees for that handle. Rows two onwards contribute only their line item. If row two has a different address or a different cadence, it is discarded with no warning. Sort your sheet by handle and check the first row of each group.

The first row also has to carry its own line columns — it is not a parent row. And re-uploading a handle replaces its line items wholesale rather than adding to them, which is what you want when fixing a mistake — but only before you activate. Once a handle has been activated, re-importing a corrected row does nothing you can see: the activated row is no longer in the imported list, so there is no Activate billing button to press, and activation short-circuits on any handle already marked migrated. Mistakes found after activation have to be fixed on the live contract in Shopify, or the contract cancelled and re-imported under a new handle.

Commas inside quoted fields are handled. Daima's parser respects double quotes, so "123 Main St, Apt 4" and "Doe, Jane" import intact, as do escaped double-quotes ("") and line breaks inside a quoted field. You do not need to strip commas out of addresses, names or plan names.

What the parser will not accept is a different delimiter. A semicolon-separated file — which is what Excel produces on a machine set to a European locale — is read as one single column and rejected with Missing required columns: handle. Save as comma-separated UTF-8. The one comma hazard left is a value that contains a comma and has lost its surrounding quotes through hand-editing: that row shifts every following column by one and imports without an error.

Spreadsheets damage this file, and some of the damage is permanent. Postcodes lose leading zeros (07030 becomes 7030), long IDs turn into scientific notation (4.72295E+13, which then reads as a plausible but completely wrong variant ID), and accented characters can be mangled if the file is saved in the wrong encoding. Daima strips the stray apostrophe that Excel and Sheets put in front of long numbers, so that one is handled — the rest are not.

You can't avoid a spreadsheet entirely here, because you have to join files and rename columns. So: import into your spreadsheet with every column set to text, not automatic; save as UTF-8 CSV, not the plain "CSV" option on Windows; and check a handful of postcodes and variant IDs against Shopify before you upload. Semicolon-separated files are rejected outright, as are files saved with classic-Mac line endings. Keep the original Recharge downloads untouched so you can start again.

Step 3 — Import, review, then activate

In the Daima admin go to Contracts and choose Import CSV. The upload is capped at 10 MB, so a very large store needs splitting into several files.

Importing changes nothing and charges nobody. Imported contracts are records in Daima only: nothing exists in Shopify, and no customer is billed, until you activate.

Read the success message carefully. It counts unique handles, not rows — a 500-row file of multi-product boxes might correctly report 120 contracts. And if every row was skipped, for example because the handle column was misnamed, you still get a success message: Successfully imported 0 contract(s). Zero is a failure, not a success.

The imported list shows the 25 most recent rows and does not page, so on a large import you will not see everything you uploaded. Activation is not limited to what's on screen.

Activate with Activate billing on a single row, or in a batch. Batches run ten at a time and tell you how many are left; click again to run the next ten. Failed rows aren't retired — they stay in the queue, get retried ahead of untouched rows, and keep counting toward the number remaining. So if a whole batch fails, clicking again just retries the same ten: fix the underlying data first. Each activation creates a real Shopify subscription contract with the same products, prices and schedule, so the customer resumes where they left off.

If a contract's next billing date is today or in the past, Daima advances it to the next occurrence on that cadence and nobody is back-billed for the gap. Today counts as past here: a contract due today is advanced a full cycle rather than billed today. A monthly contract dated eight months ago lands on the next occurrence of that day of the month — later this month if that day hasn't come round yet, otherwise next month. Days 29, 30 and 31 are the exception: a monthly date that has to pass through a shorter month overflows it — a 31 January date lands in early March — and then sticks to that new, earlier day permanently. If month-end billing matters to your customers, move those dates to the 28th or earlier in your CSV and re-upload those rows before you activate.

A date Daima can't read becomes tomorrow. There is no error for this. A missing date, or a 15/03/2026-style day-first date, is silently treated as tomorrow — and an ambiguous day-first date like 03/04/2026 (3 April to you) is read US-style as 4 March, a real date and silently a month wrong. Use YYYY-MM-DD throughout, and spot-check the next billing dates after activating.

Once a row is activated it disappears from the imported list, because the real Shopify contract now appears in the contracts list above it. A row that activated but has no usable payment method disappears too, and is counted in the warning banner rather than shown to you. Rows that failed outright stay put, with the reason printed under the button.

Step 4 — Cancel in Recharge, then uninstall

This is the step that protects your customers, and the one most easily skipped.

The moment you activate in Daima, each migrated customer has two live subscriptions — the new Daima contract and the original in Recharge. If both remain active, they will be charged twice. Keep that window short and deliberate.

  1. Before you cancel anything in Recharge, export what Recharge holds that Daima has no column for — charge history, cancellation reasons, subscription properties, store credit, loyalty state. Once the account is closed you are relying on Recharge's retention window.
  2. Activate the contracts in Daima.
  3. Spot-check several: correct customer, correct product and variant, correct price, correct quantity, sensible next billing date, address intact.
  4. Confirm the migrated contracts are actually billable — check the count in the "awaiting a payment method" banner against the number you just activated. A count that matches everything you activated is a permissions problem, not a customer problem.
  5. Go into Recharge and bulk cancel the original subscriptions — there's a bulk tool, you don't have to do these one at a time. Recharge asks you to do this before cancelling the account, along with unpublishing the widget and turning off the customer portal settings that let customers reactivate; otherwise a cancelled Recharge account can switch itself back on when it sees orders processing.
  6. Only then cancel your Recharge account and uninstall the app, if you want to.

Do not use uninstalling as a shortcut for cancelling. Shopify will cancel app-owned contracts 48 hours after uninstall, but it does so silently, on its own timer — and once the app is gone you cannot pause, fix or extend anything that didn't migrate cleanly.

Two things Recharge documents about its own side that are worth knowing here: cancelling your Shopify store does not stop activity on a Recharge account, and a cancelled Recharge account can reactivate automatically if it still detects order processing in your store. Confirm on Recharge's side that billing has actually stopped rather than assuming it. Keep your exported CSVs until the whole migration is confirmed.

Troubleshooting

"Missing required columns: handle"
The header row has no column named exactly handle. Daima trims spaces around header names, so that isn't it — look for a capital (Handle), a different name entirely, or a delimiter that isn't a comma. If your spreadsheet saved with semicolons or tabs, Daima sees the entire header row as one column.

"CSV file is empty or has no data rows"
Either the file is header-only, or it was saved with classic-Mac line endings, which collapse the whole file into one line. Re-save as a standard UTF-8 CSV.

"Successfully imported 0 contract(s)"
Not a success. Every row was skipped for having a blank handle. Usually the handle column is misnamed or the wrong column was mapped into it.

"Customer not found in Shopify (…)"
The customer_id or customer_email doesn't match a customer in this store. The commonest cause on a Recharge migration is using Recharge's internal customer ID instead of the Shopify one. If the message reads (id null), both columns were empty for that row.

"No line items with a variant_id — re-import with line_variant_id populated"
That handle has no row with a value in line_variant_id. Every contract needs at least one line with a Shopify variant ID.

"No shipping address in the CSV — include delivery_address_address1, city, and country_code columns"
The message shortens the names; the actual headers are delivery_address_address1, delivery_address_city and delivery_address_country_code. All three must be present and non-empty on the first row of that handle.

An imported row has no "Activate billing" button
Its status is something other than ACTIVE or PAUSED. Cancelled and expired rows can't be activated — they show a Delete button instead, and batch activation skips them. Re-import with the right status if the row should have been live, or delete it. The guard behind this reads Only ACTIVE or PAUSED contracts can be activated (this one is …), but the button is hidden before you can hit it.

"Contract create rejected: …"
A userError from Shopify on the contract itself — a currency your store doesn't support, or an address Shopify won't accept.

"Line add rejected (variant …): …"
A product ID where a variant ID should be, or a variant that no longer exists.

"Contract create returned no draft: …"
Shopify rejected the request itself rather than the data in it, which is what a value outside one of Shopify's fixed lists does. Almost always a cadence_interval that isn't exactly DAY, WEEK, MONTH or YEAR, or a delivery_address_country_code that isn't a real two-letter code. Fix the value, re-import that handle, activate again.

"Delivery method shipping address zip is invalid"
Usually a spreadsheet artefact rather than a genuinely bad postcode. Daima strips the leading apostrophe Excel and Sheets add to long numbers, so retry the activation first; if it persists, check the postcode for lost leading zeros.

"Customer has no stored payment method — they must add one before billing can succeed"
Recorded against the contract, and reported to you as the banner and toast counts above rather than as an error on a row. Where there's no usable payment method on the Shopify customer record, the contract still imports and activates — Daima flags it, and billing won't succeed until that customer adds one. In practice that's PayPal and wallet-only subscribers, who you'll need to email and ask to re-subscribe. Do that before you cancel their Recharge subscription.

"Payment method scope not granted — customer must add a payment method before billing can succeed"
Also recorded against the contract and counted in the same banner, but with a different cause: this is Daima's permission, not your customer's card. Attaching a stored payment method needs Shopify's protected read_customer_payment_methods scope. Where that approval isn't in place on your store, every activated contract is created unbilled and flagged this way, including customers whose card is perfectly good. If that count matches every contract you activated rather than a scattered few, stop before you cancel anything in Recharge and email [email protected].

Running both apps in parallel

If you're mid-term on a Recharge plan and can't cancel yet, you can install Daima alongside Recharge and test it on a single new product line before you commit. The two apps can coexist: each can only see and bill the contracts it owns, so they cannot fight over the same contract.

What they can do is bill the same customer twice, if you activate a migrated contract in Daima and leave the Recharge original running. Parallel testing is safe with new subscribers on a separate product. It is not safe with migrated ones.

If you'd rather not reshape the file yourself

Support still does this, and it is a real option rather than a formality. Email [email protected] with the subject line "Migrating from Recharge", before you cancel anything, and include:

  • Your Shopify store URL, so we can match customer IDs
  • Your Recharge exports as downloaded — not re-saved from a spreadsheet
  • Approximate active subscriber count
  • Whether you want your whole book migrated or a small batch first
  • Your preferred go-live date
  • Whether any subscribers are on prepaid, bundles, or ongoing discounts, since those need deciding case by case

There is no setup fee and no migration fee either way. Some rough guidance on scale, which applies whether you do it yourself or we do:

  • Under 500 active subscribers — comfortably a self-serve job, usually an afternoon including the checks.
  • 500 to 5,000 — do a small batch first, confirm it billed correctly on the next cycle, then run the rest. Remember the 10 MB upload cap and the ten-per-click activation.
  • Above 5,000, or any store with prepaid, bundles or heavy discounting — email us and we'll stage it with you rather than have you find the edge cases in production.

If we're doing the reshaping, expect the file back within one business day for stores under 500 subscribers, two to three for 500 to 5,000, and a scheduled kickoff for anything larger. We'll send you a sample of the imported rows to confirm before running the rest, so plan your go-live date a couple of days after you send the exports rather than the same day.

After you're live on Daima

Once contracts are Daima-owned, everything else follows: they appear in your dashboard, count toward analytics and revenue, feed churn prediction if you are on Pro, and — the thing your customers will notice — become manageable in the Daima customer portal, where they can skip a delivery, pause, resume, move their next billing date, swap a product or cancel themselves.

The portal is the one exception: it is a page you add to your Shopify customer accounts from your Shopify admin, and no store has it until the merchant puts it there. Your subscribers can already manage themselves in Recharge, so add it before cutover — otherwise they land on Daima with nowhere to go and start emailing you instead. The customer portal doc has the steps.

Worth doing next: confirm your subscription plans match what those customers signed up for, read up on the customer portal so you know what subscribers can now self-serve, and check the dashboard to see the migrated subscribers appear. If you also have contracts sitting in Shopify's own Subscriptions app, the Shopify Subscriptions guide covers that shorter version of the same job. When your migrated base changes the economics, compare Free and Pro.