How an import works
An export is used for two things only: who each purchase belongs to, and how to find it at the store. RevFox then fetches the purchase from Apple or Google, with its renewals, prices, refunds and environment.
- Open Integrations → Migration and upload the CSV.
- Check the column mapping. Columns of the supported platforms are detected; any can be changed.
- Pick the App Store and Play apps the purchases belong to, and start.
- Rows are processed in the background. The page shows progress, and failed rows with their error. Retry failed queues them again.
Running the same export twice is safe: purchases and events are recorded once.
What a row needs
| Column | Required | Notes |
|---|---|---|
| Customer ID | Yes | The ID your app will give the RevFox SDK. |
| Other customer IDs | No | Earlier or anonymous IDs merged into the customer. Each becomes an alias. |
| Store | No | app_store, play_store and common spellings. Other stores are skipped. When missing, GPA. order IDs and tokens mean Play, numeric IDs mean App Store. |
| Original transaction ID or transaction ID | For purchases | App Store transaction ID or Play order ID. The original ID is preferred. |
| Play purchase token | No | Used instead of the order ID when present. |
| Product ID | No | Only for Play one-time products listed by token without an order ID. |
| First seen | No | The customer's first-seen date becomes the earlier of this and their first purchase. |
| Attributes | No | JSON objects of reserved and custom attributes, such as RevenueCat's. Reserved names are converted: $displayName becomes $display_name, $gpsAdId becomes $gaid, and $deviceVersion is split into model, manufacturer, OS version and platform. |
| Country, sandbox | No | Used for Play subscriptions Google no longer answers for. |
| Email, display name | No | Stored as $email and $display_name. |
| Benefit, start and expiration date | For promotional rows | Rows with store promotional become promotional grants. RevenueCat's rc_promo_<entitlement>_<duration> product IDs are read too. Create benefits with the same identifiers as your RevenueCat entitlements first. |
Rows without a purchase import the customer and their attributes only. The browser groups rows of the same subscription, such as one per renewal, before uploading.
What RevFox does with each row
- App Store: looks the transaction up with the App Store Server API, in production and then sandbox. Needs the app's In-App Purchase key.
- Play: resolves an order ID to its token with the Android Publisher API. Google stops answering for a subscription about 60 days after it ends; RevFox then rebuilds it from its orders, taking country and test status from the export.
- The purchase then goes through the normal purchase path for the row's customer, which fills in its full history from the store.
- Billing issues, cancellation dates and extended access in the export are recorded too, since stores no longer report them for old periods.
- A Play purchase that a notification recorded under a placeholder before the import is moved to the imported customer.
Rows run one at a time on SQLite and four at a time on PostgreSQL.
Imported events reach webhooks and analytics like any other. Make your backend ignore repeats by store transaction ID, or turn endpoints off during the import; turning them back on does not replay events.
Recommended cutover
- Add the apps with their store credentials, import store items, and set up benefits and packages.
- Point App Store Server Notifications and Play real-time developer notifications at RevFox. Renewals of imported subscriptions then attach to the imported customers.
- Import a full export.
- Ship the app version with the RevFox SDK, using the same customer IDs. Shortly before release, import a fresh export to pick up purchases made since.
Limits
- Refunded or voided purchases are imported with their refund, so they grant nothing.
- Purchases from stores RevFox does not verify, such as Stripe, Amazon or Paddle, are skipped.
