Skip to main content
POST
The heart of a migration request is selected_entities — the list of entity groups to copy from the source store to the destination. This page explains everything that list controls: what you can migrate, how entities depend on one another, how bulk differs from selective, and what happens when you pass something the engine doesn’t recognise.
Unrecognised entity keys are silently ignored — they are not rejected. The API validates only that selected_entities is a non-empty array of strings; it does not check the values against a known-entity list. A typo like "product" (instead of "products") passes validation, migrates nothing, and returns no error. Use the exact keys from Supported entities.

Bulk vs selective migration

A single request runs in one of two modes, decided entirely by whether you send a selection: A run counts as selective only when selection contains at least one non-empty array. An empty selection: {} is treated as bulk.
The StagingPro UI’s Selective Migration screen offers six pick tabs — Products, Categories, Pages, Promotions, Themes, and Page Templates. The request examples on this page include one example per tab (Selective — Products tab, and so on), each sending exactly the payload the UI sends: only that tab’s entity keys, that tab’s selection array, and conflict_strategy: "update" (selective runs update existing destination items — that is the UI’s fixed behaviour). Selective picks also scope entity counts and the forecast, so a ten-product pick is sized as a ten-product run.

Supported entities

Entities fall into families. Each parent entity has a key you place in selected_entities; most parents also own child entities that carry the detail beneath them. Every child key is itself a valid selected_entities value — selecting a child alone forces its parent to run so the id-mapping exists (see Dependencies).
Selecting a parent does not include its children — each child is opt-in. selected_entities: ["products"] migrates only the product record (name, price, SKU, description). It does not bring variants, images, options, modifiers, custom fields, metafields, bulk pricing, reviews, or channel assignments — you must list each of those keys explicitly. To migrate a complete catalogue, include the child keys (see the “Complete catalogue” request example above). The one exception: custom_fields travel automatically on a selective product run.
  • options is not independently meaningful — variant options migrate automatically as part of variants. There is no options-only migration, so to move them, select variants.
  • variant_metafields needs variants, and complex_rules needs modifiers.
  • When both categories and products are selected, product sort order (“featured” ordering within a category) migrates automatically — there is no separate key for it.
The theme key is page_templates, not theme. theme is accepted by the counts badge only and does not trigger a migration.
content_assets and page_widget_images copy image files over WebDAV, so they only do something when (a) the destination store has WebDAV credentials configured, and (b) the run also migrates the content that references them (pages, blog posts, banners, or page_widgets). Otherwise they are skipped with a note.
Two different “template” concepts — don’t confuse them:
  • The page_templates entity (in selected_entities) migrates the theme. For selective theme picks, pair it with selection.themes (uuids) and theme_activation.
  • The selection.page_templates picks (pages/… values) migrate Page Builder template content and are driven by the page_widgets entity, not page_templates. If you send selection.page_templates without page_widgets in selected_entities, the picks are silently ignored.
Customer addresses, form fields, and store credit migrate inline with the customer record rather than as separate progress rows. Unlike most child keys, they do not force the customers parent — you must select customers (or customer_groups/customer_attributes) as well, or they do nothing.
To migrate only certain order statuses, add order_status_{id} keys alongside orders — for example ["orders", "order_status_11"]. With no status keys, all statuses migrate.
Grouped under Store Settings in progress. Each is a direct copy from source to destination; channel-scoped ones apply per storefront using your channel mapping.
Grouped under Storefront Settings in progress. Most apply per storefront (channel).

Dependencies and automatic includes

Some entities can’t stand alone — the engine pulls in what they need so references resolve on the destination. Passing a wrong combination doesn’t error; the engine adds the prerequisites or drops the orphaned reference with a warning. Selecting a child forces its parent — but not the reverse. Selecting metafields runs products; brand_metafields runs brands; category_metafields runs categories; page_widgets runs pages. The parent has to run so its source→destination id-map exists. The relationship is one-way: selecting the parent (products) does not pull in its children — list each child key you want (see the warning under Supported entities). Selecting products auto-pulls the brands and categories they reference. On a selective product run, the engine reads each picked product’s brand_id and category ids and migrates only those brands and categories (plus category ancestors, so the tree is intact). A product’s custom fields also travel automatically on a selective product run, even if custom_fields isn’t listed. Hierarchies auto-include ancestors. Selective category picks pull in their parent categories; selective page picks pull in their parent pages. Some children need a sibling. variant_metafields needs variants (no variant id-map without it); complex_rules needs modifiers (rules reference modifier values). If the sibling is absent, that child is skipped with a note rather than failing the run. Cross-entity references are remapped or dropped. Page widgets, promotions, and template associations rewrite their entity ids through whichever id-maps the run built. A reference to something not in the migration (for example a promotion targeting a category you didn’t migrate) is dropped with a warning, because it would 404 on the destination. Some storefront settings reference the catalogue. Two settings carry catalogue ids and so depend on those entities migrating in the same run:
  • search_contextual_filters — BigCommerce contextual filters are configured per category (Contextual Filters), so each context’s category_id is remapped through the category id-map. It needs categories.
  • redirects — 301 redirects that point at a product, category, brand, or page are remapped through those id-maps. It needs the entities its redirects target.
The API does not auto-add these prerequisites — the StagingPro UI does. If you call the API with search_contextual_filters but omit categories, the category id-map is empty and every category-scoped filter context is dropped with a warning — the setting appears to migrate but the per-category overrides are silently lost. Always include categories alongside search_contextual_filters (and the relevant catalogue entities alongside redirects).

Migration order

Entities always migrate in a fixed order so dependencies land first — you don’t control it, and the progress display’s order is cosmetic. Each step mirrors a real reference in the BigCommerce API, so an entity is never created before the ids it points at exist on the destination. The real order is:
1

Theme, then brands, then categories

The theme uploads first — BigCommerce themes are store-global and activated per storefront, so they have no catalogue dependency (Multi-Storefront guide). Brands and categories go next because a product carries a brand_id and a categories array, so those ids must resolve first (Create a Product).
2

Pages, then products and their children

Product children — images, variants, modifiers, metafields, locale, and so on — are nested sub-resources under /catalog/products/{id}, so they migrate once the product id-map is built.
3

Page widgets, then store and storefront settings

Page Builder widgets run after the catalogue: a widget placement takes an entity_id pointing at a specific product, brand, category, or page, so those ids must be mapped first. Store and storefront settings follow for the same reason — the ones that carry catalogue ids (per-category contextual filters, and 301 redirects that point at a product/category/brand/page) can only remap those ids once the catalogue has migrated.
4

Content, inventory, customers, pricing

Email, blog, banners, scripts, inventory locations, customer groups, customers, customer attributes, price lists. Customer groups come before customers and pricing because price-list assignments reference a customer_group_id.
5

Marketing offers, then orders

Customer segments and promotions run after the catalogue and customer groups, because promotion conditions reference categories, products, and customer group_ids. Orders run last: their line items reference product_id and the order carries a customer_id (Order Products).

Business rules that affect selection

Selecting orders, customers, or gift_certificates requires anonymise_customer_data: true. Without it the request is rejected:
These entities carry personal data, so it is anonymised on the destination regardless.
conflict_strategy controls what happens to an entity that already exists on the destination:
  • skip (Add New Only, default) — leave existing items untouched.
  • update (Update Existing) — additively update changed fields and child items.
  • replace (Make Exact Copy) — update, then delete destination-only items so the destination mirrors the source.
replace is refused when the destination is a live production store, because it deletes data:
On a selective run, replace still updates picked items but does not prune — a partial view of the source can’t distinguish a genuine extra from an unpicked item.
A store can never migrate onto itself — identical source and destination hashes are rejected. A store labelled Production can never be a destination.
With source_channel_id + destination_channel_id, the run maps one storefront to another. Set channel_scoped_products: true to migrate only the products assigned to that source storefront; otherwise all products migrate and are assigned to the mapped destination channel.
When selection.themes is present, the bulk activate_theme flag is ignored. Use theme_activation to activate a picked theme on specific destination channels. Two rules are enforced: every key must be a picked theme, and a destination channel may be activated by only one theme (a channel has exactly one active theme). selection.page_template_globals must be a subset of selection.page_templates.

Invalid values and errors

Because unknown keys are accepted without complaint, the safest way to build selected_entities is to copy keys directly from Supported entities above rather than typing them from memory.

Authorizations

Authorization
string
header
required

A bearer token from Login, sent as Authorization: Bearer <token>. Valid for 10 days; scoped to the user and organisation it was issued for. Rotating or disabling the organisation's API credential immediately invalidates all outstanding tokens. Browser calls from a signed-in app.vortexiq.ai page are also accepted via session cookie — see Authentication.

Body

application/json
source_store_hash
string
required

BigCommerce store hash to migrate from. Must be connected to your organisation.

destination_store_hash
string
required

BigCommerce store hash to migrate to. Must differ from the source.

selected_entities
string[]
required

Which entity groups to migrate — for example products, categories, brands, pages, page_templates, promotions, orders, customers. Child keys (e.g. variants, metafields, page_widgets) and settings keys are also valid and force their parent to run. Unknown keys are silently ignored, not rejected. See the full catalogue, dependencies, and rules above.

Minimum array length: 1
mode
enum<string>
default:full

full migrates; dry-run walks the migration without writing; verify compares only; counts totals only.

Available options:
full,
dry-run,
verify,
counts
anonymise_customer_data
boolean
default:false

Required true when orders, customers, or gift_certificates are selected.

conflict_strategy
enum<string>

How an entity that already exists on the destination is handled:

  • skip — Add New Only (default): leave existing items untouched.
  • update — Update Existing: additively update changed fields.
  • replace — Make Exact Copy: update, then delete destination-only items. Refused against a production destination.
Available options:
skip,
update,
replace
activate_theme
boolean

Bulk theme migration: activate the migrated theme on the destination rather than only uploading it. Ignored when selection.themes is present — use theme_activation instead.

auto_heal
boolean

Accepted for compatibility only. Self-healing is always enabled.

source_channel_id
integer

Multi-storefront: the source storefront to migrate from. Pair with destination_channel_id.

Required range: x >= 1
destination_channel_id
integer

Multi-storefront: the destination storefront to map onto.

Required range: x >= 1
channel_scoped_products
boolean

Migrate only products assigned to source_channel_id. When false, all products migrate and are assigned to the mapped destination channel.

channel_map
object

Explicit source channel id → destination channel id map, for mapping several storefronts at once.

source_storefront
string

Source storefront name, recorded for display in History.

destination_storefront
string

Destination storefront name, recorded for display in History.

selection
object

Selective migration picks. Parents and ancestors are included automatically, and products pull in their brands and categories.

Find the ids to pass here in the StagingPro app's Selective Migration tab. A selection also scopes entity counts and the forecast.

theme_activation
object

Selective themes only: which destination channels to activate each picked theme on, keyed by source theme uuid. Omit to upload the themes without activating them.

Every key must appear in selection.themes, and a destination channel may be targeted by at most one theme — a storefront channel has exactly one active theme.

Example:

Response

Migration queued.

requestId
string

Identifies the run. Use it with every other migration endpoint.

status
enum<string>
Available options:
queued
mode
enum<string>
Available options:
full,
dry-run,
verify,
counts
forecast
object | null

Sizing forecast computed at kickoff, when available.