Skip to main content
This is the same operation as Products → Combine → Marketplaces. Exact-SKU catalog products become one master product. Existing marketplace listings keep their IDs, content and live/unpublished state. Other OmniCommerce products are archived, with history retained. The merge itself does not publish changes. The master keeps its content, images, price and stock. Stock is not added together. Distinct listings in the same connected store block a merge. Listings in different stores, including stores on the same marketplace, can be retained. Every supported marketplace uses the same merge service.

Discover duplicates

Use credentials for the intended organization. Reading requires catalog:read; refreshing a scan and merging require catalog:write.
The scan runs durably in the background. An already queued/running scan is reused. Read data.status until completed with a bounded wait/backoff; stop and inspect errorMessage on failed. idle means a scan has not been saved. Results are from the latest saved scan; requestedAt and computedAt show its freshness. The shared UI scan currently examines at most the 5,000 most recently updated non-archived root products. Completion does not establish full coverage of a larger catalog. List rows are in items. Each row’s duplicateMatches includes peer productId, name, SKU, score and match reasons. Use the root id plus its exact_sku peer IDs as candidate targets, removing repeats. Follow pagination.nextCursor and nextOffset until hasMore is false for the selected scope. A single page or representative row is not the entire catalog. detail=summary omits duplicate evidence; use full. duplicateStatus=active restricts discovery to active products; omit it to include drafts as in the UI. duplicateType=content and variants expose other UI discovery filters, but matching content/model signals alone do not make products eligible for this merge. The server partitions and validates exact-SKU groups. Send 2–20 distinct products per request, at most 10 groups. Do not silently truncate larger groups.

Choose and review the master

Inspect data.groups[].products for names, SKUs, currency-labeled prices, stock and every per-store listing. Inspect each group’s masterSelections: A domain block returns HTTP 200 with ok: false; the preview and eligibility are still in data. In particular, errorCode: stock_source_requires_master means the current master choice cannot preserve stock ownership. Choose an allowed master and preview again. Other blockers, such as running jobs, variants, bundles, currency differences and same-store listing conflicts, remain enforced.
This is a real read-only validation. CLI --dry-run only prints the request and does not perform server validation. Review each successful group’s productIds (master first), sku and preserved listings before approving a merge. The UI dialog’s Dry run button opens chat with the selected products and master. Choose Run dry run in the tool card. The server runs the same merge transaction, validates database constraints and rolls back its writes. Products, marketplace links, references and audit records remain unchanged; it emits no product-update events or duplicate scan. A real merge needs a separate approval. CLI and SDK callers use dryRun: true on the merge operation for this server-side simulation. This differs from the CLI’s transport-only --dry-run option:
Dry-run responses include dryRun: true; counts and per-product results describe validation outcomes. mergedProductIds is empty and wouldMergeProductIds contains the sources that passed simulation. Partial failures remain explicit.

Merge the reviewed groups

Pass expectedGroups from the successful preview. This pins group membership, master and SKU; changed or omitted groups fail rather than being silently merged.
Replace example IDs and SKU with the reviewed values. Inspect data.success, succeededCount, failedCount, groups and ordered per-product items. Groups commit independently; report partial failures. Do not treat HTTP 200 as proof that every product merged. The server rechecks stock connections and other constraints inside the merge transaction. A separate authorized publish/update is needed to send content or prices to existing marketplace listings.

TypeScript SDK

Preview and merge responses are typed from the canonical schemas, including master eligibility and per-target results. The example continues only for a single group with one eligible master; for multiple groups, choose and review one master per group and include every approved group in the batch.

Python SDK

AsyncOmni exposes the same operations with await. Python request arguments use snake_case; response fields and nested expectedGroups members retain camelCase. CLI --help and --schema include operation guidance generated from OpenAPI, so terminal agents can discover these rules without a browser session.