Paste a product URL from any public Shopify storefront and get a real product in your store: title, description, images, options, and every variant with its own price, compare-at price and SKU. In the dashboard this is My Products → Import Products → From a Shopify link. The same two endpoints back the API.

Preview first

preview reads the source store and returns exactly what would be created. It writes nothing, so it is safe to call before showing a confirmation step.
A link that cannot be read comes back as ok: false with a human-readable error rather than failing the whole call.

Import

  • status0 draft (default), 1 active, 2 archived. Imports default to draft so nothing reaches your storefront before you have reviewed the pricing.
  • skip_existing — defaults to true. A link whose source product this store already imported comes back as "skipped": true with the existing product_id instead of creating a duplicate. Set it to false to import a second copy deliberately.
  • Up to 20 URLs per call. One bad link never aborts the batch: the response is 207 Multi-Status when some succeeded and some failed, 200 when all succeeded, and 502 when none did.
  • A storefront resync (products.json → CDN) is scheduled once per successful batch.
Scope: write_products. Preview needs it too — it performs outbound fetches on your behalf.

From an agent (MCP)

Two dtc_* tools wrap the same endpoints, so an agent can do this without writing HTTP:
Both take catalog:write — preview included, since it drives outbound fetches on the store’s behalf. The store is bound to the agent key, so there is no store argument.

What gets copied

Money is copied verbatim in the source store’s currency — no conversion is applied. Check pricing before publishing if the source store sells in another currency. Inventory is not imported. Public storefronts expose whether a variant is in stock but never the actual count, so imported variants start untracked rather than with an invented number.

Accepted URL shapes

All of these resolve to the same product:
The importer reads the public storefront — no Shopify app, OAuth or Admin API token is involved. It tries /products/{handle}.json, then /products/{handle}.js, then the product page’s embedded JSON, and reports which one worked in source. Some stores block automated reads on every one of those routes. When that happens the item comes back with:
This store blocks automated reads of its product data. Try again later, or add the product manually.
There is no workaround from our side — the store is refusing the request. Add the product manually with POST /products instead.