Skip to main content

Migration process explained

Learn how you can migrate to RecurrinGO!

Written by Andrey Gadashevich

Migrating to RecurrinGO!

Our support team runs your migration for you — you prepare the CSV, we validate and import it.

Step 1: Prepare your file

Export your subscription data as CSV, following the CSV format section below. Send it via the in-app chat on the Migration page (Settings → Migration).

Step 2: Dry run (validation only)

We run a dry run first — nothing is changed yet. We send back any rows with problems and why, typically within 1 hour if your CSV matches the required format.

Files with formatting issues may take longer, depending on the number of corrections needed.

What the dry run can and cannot catch. The dry run checks each row on its own: missing required fields, malformed dates, a bad gateway identifier, a PayPal ID that doesn't start with B-, an unsupported payment_gateway value. It does not contact Shopify for your data, so the following problems only surface during the real import:

  • rows of the same subscription not placed next to each other;

  • rows of the same subscription disagreeing on a subscription-level field (see Step 3 rules below);

  • a variant_id that doesn't exist in your store (or whose product can't be resolved);

  • no matching Shopify customer, or an email matching more than one customer;

  • a customer with no saved payment method in Shopify (Scenario A);

  • the gateway rejecting or revoking the payment method (Scenario B).

Because of this, expect a second round of fixes after the real import on larger files — that is normal and safe: failed subscriptions are skipped, not half-created.

Step 3: Fix and resend

Correct the flagged rows and resend. We repeat validation until the file is clean.

Step 4: Real import

We run the live import. A row that fails validation, a group whose rows disagree, or an identifier we can't resolve skips that whole subscription — no half-built subscription is created from those. Rare infrastructure-level failures (a Shopify API error mid-build) are reported to you individually and re-run.

Step 5: Results

We send you a summary per subscription: imported / skipped / failed, with the reason for each failure. Reasons come from the import log, so every skipped subscription is traceable to a row number and a cause.

Good to know — re-runs:

  • Neither scenario deduplicates subscriptions. The import does not remember which subscriptions it already created, so re-importing a file that contains an already-migrated subscription creates a second subscription for that customer — and, once active, a second charge. A re-run must contain only the subscriptions that still need importing.

  • What is remembered in Scenario B is the payment method: a gateway reference that was already vaulted into Shopify is reused instead of being vaulted again. That makes a Scenario B re-run cheap and safe for payment methods, but it does not protect against duplicate subscriptions.

  • Using status: PAUSED on import is a useful safeguard while your old platform is still live, but it is not duplicate protection — see the post-migration checklist.

Common reasons a subscription fails: wrong/missing gateway identifier, a PayPal ID not starting with B-, no matching customer (and auto-create not enabled), an email matching more than one Shopify customer, the customer has no saved Shopify payment method (Scenario A), rows of the same subscription not adjacent or disagreeing on a subscription-level field, a variant_id that doesn't exist in the store, the gateway not yet chargeable (Stripe vault not transferred, PayPal not approved).

CSV File Format for Migration into RecurrinGO!

Before you start

  • Historical and analytics data is not migrated. Migrated customers and subscriptions will appear as new as of the migration date — past orders, analytics, and reporting history stay in your previous platform. Each migrated subscription gets exactly one placeholder order record (named Imported) so cycle counting starts from 1.

  • Bundle (box) and prepaid subscriptions aren't supported by this template yet. If you use these, contact support directly — since migration is handled manually by our team, these can still be migrated as an individual, custom case.

First, figure out which scenario you're in — it determines which columns you need.

  • Scenario A — Moving from another subscription app (Recharge, Bold, Appstle, etc.). Your customers and their payment methods are already in Shopify; only the subscriptions need to be rebuilt.

  • Scenario B — Moving from a payment gateway directly (Stripe, Braintree, Authorize.net, PayPal). Payment methods are still held by the gateway and need to be recreated inside Shopify as part of the import.

Rule of thumb: if you switched subscription apps but stayed on the same Shopify checkout, you're Scenario A. If you're bringing card/billing references out of Stripe/Braintree/Authorize.net/PayPal directly, you're Scenario B.

General file requirements (both scenarios):

  • CSV format, UTF-8 encoded, with a single header row.

  • One row = one product. A subscription with several products is several rows sharing the same id, placed directly next to each other in the file.

  • Subscription-level fields must be repeated, with identical values, on every row of the group. They are read from the first row, but the import compares them across all rows of the group and skips the whole subscription if any row disagrees — and a blank cell counts as a disagreement. Do not leave them empty on the 2nd and later rows.

    The compared fields are: customer_id, customer_email, next_billing_date, order_placed_date, status, final_amount, currency_code, delivery_price, is_auto_charging, payment_method_id, interval, interval_number, interval_type, shipping_address1, shipping_zip, shipping_country, shipping_country_code, shipping_province, shipping_province_code, billing_address1, payment_gateway, gateway_customer_id, gateway_payment_method_id.

    Simplest safe rule: fill every column on every row of the group, and vary only the per-line columns (product_id, variant_id, quantity, final_price, requires_shipping).

  • Products/variants referenced in the file must already exist in your Shopify store.

Additional prerequisites — Scenario A:

  • Each customer already exists as a Shopify customer.

  • Each customer has a saved payment method in Shopify (a specific one, or leave it blank to use their existing method automatically). If a customer has no saved method, that subscription can't be migrated this way.

Additional prerequisites — Scenario B:

  • Your store must be enabled for subscription migration by Shopify. This is a store-level permission on Shopify's side (not something the app can switch on); the import refuses to start without it. Request it from Shopify before sending the file — our team verifies it for you first.

  • The gateway is connected to your Shopify store and supports subscriptions.

  • Stripe only: if moving to Shopify Payments, your Stripe vault must first be transferred into the Shopify Payments Stripe account — request this from Stripe support directly. Until transferred, migrated Stripe methods aren't chargeable.

  • PayPal only: RecurrinGO! checks whether PayPal subscription support is enabled on your store before migrating — if it isn't, the migration won't go through. Your PayPal account also needs reference transactions approved (request from PayPal).

  • PayPal saved inside Braintree: export these as PayPal billing agreements and list them as PayPal rows — not as Braintree.

  • The RecurrinGO! app must have been re-opened/re-authorized after being granted permission to vault payment methods — our team will confirm this for you.

  • Billing address must be linked at the payment method level in the gateway before migration (Stripe, Braintree, Authorize.net). A missing billing address cannot be added or fixed after the migration — it must be verified and updated directly in the gateway beforehand. Note some gateways store billing address at both the customer level and the payment-method level; make sure it's present specifically on the payment method. PayPal is the exception: the billing_… columns in the CSV are sent to Shopify as the billing agreement's address, so for PayPal rows you can supply it in the file.

Template headings explained

"Required" below means the import rejects the row without it. Several columns are formally optional but produce a silently wrong subscription when left blank — those are marked effectively required; see the defaults table after this section.

Column

Required?

Description

id

Required for multi-product subscriptions

Your subscription's ID from the old system. Groups rows belonging to the same subscription — keep them adjacent in the file. A single-product subscription can technically go without it, but always fill it: it's what our failure report points at.

customer_id

Required (Scenario A) / one of customer_id/customer_email (Scenario B)

The customer's numeric Shopify ID.

next_billing_date

Effectively required

Date of the next charge, e.g. 2026-07-01. A blank value is not an error — it silently becomes today. A date in the past is silently moved forward (to one week from now for auto-charge subscriptions, or to the next cycle for invoice ones), so never rely on a past date to mean "charge immediately".

variant_id

Required

Shopify variant ID (per row). Must exist in the store.

product_id

Optional

Shopify product ID (per row). If blank, it is resolved automatically from variant_id.

shipping_last_name

Required (every row)

Shipping contact last name.

shipping_address1

Required (every row)

Primary shipping address line.

shipping_city

Required (every row)

Shipping city.

shipping_zip

Required (every row)

Shipping postal/ZIP code.

shipping_province and shipping_province_code

One required — fill both

Validation accepts either, but the stored subscription address only keeps the province when the name column is filled. Fill both to get a complete address in RecurrinGO! and in Shopify.

shipping_country and shipping_country_code

One required — fill both

Same as above: the stored address takes the country from the code column. Fill both.

quantity

Optional

Quantity of the line. Blank = 1.

final_price

Effectively required

Price per unit of the line. This is what Shopify actually charges. Blank = 0, i.e. a subscription that charges nothing for that line.

final_amount

Optional

Total that was charged per cycle in your old system. Recorded for reporting only — it does not set the charge amount. The amount actually charged is always final_price × quantity across the lines, plus delivery_price. If blank, it's calculated from the lines.

status

Always set explicitly

ACTIVE or PAUSED. Leaving it blank does not mean "active": the subscription is created paused in RecurrinGO! and will not bill until you activate it. Set PAUSED deliberately as a safeguard against double-charging while your old platform is still live, and ACTIVE when you want billing to start.

order_placed_date

Optional

When the subscription originally started. Blank = today.

interval, interval_number, interval_type

Effectively required

Billing frequency, e.g. interval_number: 1, interval_type: month. Blank = every 1 month.

currency_code

Effectively required

3-letter currency code, e.g. USD. Blank defaults to EUR, which is wrong for most stores.

delivery_price

Optional

Shipping cost per cycle. Blank = 0 (free shipping). Charged on top of the line prices.

is_auto_charging

Required for auto-charge subscriptions (all of Scenario B)

yes = the subscription charges the saved payment method automatically. Blank or anything other than yes/on/1/true creates an invoice subscription that emails the customer a payment link instead of charging them. In Scenario B this means the payment method is vaulted into Shopify and then never used.

subscription_discount_percent

Optional

Discount percentage applied to the whole subscription (read from the first row of the group — a different value on later rows is ignored). Blank = 0.

requires_shipping

Optional

Whether the line ships physically (per row).

shipping_first_name, shipping_address2, shipping_phone, shipping_company

Optional

Additional shipping fields.

billing_… fields

Optional

Billing name/address, if different from shipping. For PayPal, used as the billing agreement's address.

What happens when an optional column is blank

There are no visible placeholders, but there are silent defaults. These are the ones that change money or timing:

Column

Blank means

currency_code

EUR

final_price

0 per unit

delivery_price

0

quantity

1

interval_number / interval_type

every 1 month

status

paused (won't bill)

next_billing_date

today

order_placed_date

today

is_auto_charging

invoice subscription (no automatic charge)

subscription_discount_percent

0

Payment columns

Scenario A — payments already in Shopify

Column

Required?

Description

payment_method_id

Optional

The customer's Shopify saved payment method. Leave blank to use the customer's first available saved payment method (we warn you when a customer has more than one, so you can decide whether to name it explicitly). If none exist, the subscription fails to import. Only used for auto-charge subscriptions.

Scenario B — payments in an external gateway

Column

Required?

Description

payment_gateway

Required

One of stripe, braintree, authorize_net, paypal.

customer_email

Required if customer_id isn't provided

Used to identify the customer when you don't have their Shopify customer_id. Must match exactly one Shopify customer; an email matching several customers fails the row. Confirm whether missing customers should be auto-created from this email.

gateway_customer_id

Depends on gateway

The customer's ID within the gateway — see table below.

gateway_payment_method_id

Depends on gateway

The payment method/token/agreement ID within the gateway — see table below.

is_auto_charging

Required — set yes

Without it the vaulted payment method is never charged (see the column table above).

Leave payment_method_id blank for Scenario B — it's created automatically from the gateway reference.

Gateway

gateway_customer_id

gateway_payment_method_id

Stripe

Customer ID cus_… (Stripe Dashboard → Customers). Required.

Payment method pm_…. Optional — blank uses the default method.

Braintree

Customer ID (Vault). Required.

Payment method token (Vault). Required.

Customer profile ID (CIM). Required.

Payment profile ID (CIM). Required.

PayPal

Leave blank.

Billing Agreement ID starting with B-, e.g. B-2X1234567Y8901234. Required.

Supported payment providers: payment already in Shopify, Stripe, Braintree, Authorize.net, PayPal.

Note on timing: each new payment method is vaulted asynchronously by Shopify and the import waits for it (up to ~30 seconds per method). Large Scenario B files therefore take noticeably longer than Scenario A ones.

Additional columns

Optional — leave blank if they don't apply: product_id, quantity, order_placed_date, final_amount, delivery_price, subscription_discount_percent, requires_shipping, shipping_first_name/address2/phone/company, all billing_… fields.

Note that currency_code, final_price, interval*, status and is_auto_charging are technically optional but should always be filled — see the defaults table above.

Sample CSV file

Two examples, depending on your scenario:

migration-sample-scenario-a.csv — payments already in Shopify

⚠️ The product_id and variant_id values in these sample files are fictional placeholders used to illustrate the CSV structure — they are not real Shopify IDs and don't need to be swapped out; the point of the sample is the format, not the values. In your own file they must be real IDs from your store.

Note how the two rows of the multi-product subscription repeat every subscription-level value identically and differ only in the line columns.


Have questions about a migration? Message us from the Migration page in Settings, or reach out to support directly.

Post-migration checklist

Once your migration is complete, use this checklist to confirm everything came across correctly before cancelling your old platform. (This is a reference list, not a saved tracker — note articles like this one don't retain progress between visits, so keep track of it yourself if needed.)

Spot-check a sample of migrated subscriptions

  • Pick a handful of subscriptions (including at least one multi-product one) and open them in RecurrinGO!.

  • Confirm the products/variants, quantities, and prices match the original subscription — a 0.00 price means final_price was blank in the file.

  • Confirm the next billing date is correct for each. Pay particular attention to subscriptions whose date was in the past in your file — those were moved forward automatically.

  • Confirm the currency is your store's currency, not EUR.

  • Confirm each subscription is the type you intended: auto-charge (charges the card) vs invoice (emails a payment link).

  • Confirm the shipping address is complete and correct, including state/province and country.

Confirm payment methods are valid

  • For Scenario A: confirm the correct saved payment method is attached (not just a method — the right one, especially for customers with multiple saved cards).

  • For Scenario B: confirm the gateway payment method was successfully converted into a working Shopify payment method (check the customer's record in Shopify).

  • Check the final report for any subscriptions marked failed or skipped, and follow up on each one individually.

Check for duplicates

  • If any file was imported more than once, check the affected customers for duplicate subscriptions — the import does not detect already-migrated subscriptions and will create a second one.

  • Double-check no subscription is active in both platforms at once for the same customer.

Activate migrated subscriptions safely

  • If you imported with status: PAUSED, confirm your old platform is fully cancelled/deactivated before switching subscriptions to active in RecurrinGO!.

  • Be aware that a customer can resume their own paused subscription from the customer portal. If the window between import and cancelling your old platform is long, tell support so we can keep the portal action out of reach until you're ready.

Wrap up

  • Cancel or deactivate the corresponding subscriptions in your previous platform.

  • Let your RecurrinGO! contact know the migration is confirmed and complete.

Migrations FAQ

Are my customers notified about the migration?

No notifications are sent by the import itself — customers are not emailed when their subscription is created. Note that once a migrated invoice subscription is active, the normal invoice email goes out on its next billing date; keep that in mind when choosing next_billing_date and status.

Are webhooks triggered during the import?

It depends on the subscription type. Auto-charge subscriptions create a real Shopify subscription contract, so subscription_contracts/create fires during the import. Invoice subscriptions don't create a Shopify contract and therefore trigger no webhook. If you use integrations (Klaviyo, analytics, etc.) that listen for subscription events, expect webhook activity for auto-charge subscriptions and plan accordingly.

Can my customers update their payment or billing info during the migration window?

Yes. After import, a subscription behaves like any other — including a paused one, which the customer can resume themselves from the portal. This has no effect on the import, which is already complete by the time the subscription is visible to the customer. If that's a risk for your rollout, tell support before the import.

What happens if a customer is missing data RecurrinGO! expects (e.g. no phone number)?

If required fields are missing (address line, city, ZIP, last name, country/region, variant), the subscription is not created. If optional fields are missing, the subscription — and the customer record if needed — is created without them. No visible placeholder text is inserted, but several blank fields fall back to a default value (currency EUR, price 0, frequency monthly, dates today, paused status) — see the defaults table in the CSV format section.

Is there a row limit for migration files?

There is no strict row limit. Very large files may take longer to process — Scenario B especially, since each new payment method is vaulted asynchronously by Shopify. If necessary, our team will split the file into batches manually. For most typical migrations, file size is not a concern.

Can I re-run a migration if I find a mistake after going live?

Yes, but the re-run file must contain only the subscriptions that still need importing. The import does not remember which subscriptions it already created, so a re-import of an already-migrated subscription produces a duplicate — in both scenarios. What Scenario B does remember is the payment method: an already-vaulted gateway reference is reused instead of being vaulted a second time.

Are bundle (box) or prepaid subscriptions supported?

Not yet via this template. Contact support directly — since migration is a manual, dev-assisted process, these can still be handled as an individual case.

Who do I contact if something looks wrong after migration?

Message us anytime from the Migration page in Settings (chat).

Did this answer your question?