Catalog API2026-11Preview
Products
A listing you saved from an import, with your title and prices and the stores it sells on.
- Shopify is where products are pushed. Orders from the marketplaces your Shopify store sells on reach us through Shopify too: Connect a store.
- A WooCommerce or Wix store keeps its own products and sends its orders with Create an order.
The Product object
idstring- Starts prd_.
titlestring- Your title. The seller's stays on the import.
statusstring- active, or paused (by you, or by a sync rule when a cost rose too far or the seller ran out).
sourceobject- Marketplace, listing link and seller in China.
options[]array- Option names, at most three, as your store shows them.
price_range, cost_rangeobject- Your prices and the seller's, across variants.
channels[]array- Where it is listed: the store, its own product id, and its status there.
syncobject- The sync rule it follows and when we last read the listing.
importstring- The import it was saved from.
{
"id": "prd_8f2k",
"title": "Heavyweight Washed Hoodie",
"status": "active",
"source": {
"marketplace": "weidian",
"url": "https://weidian.com/item.html?itemID=7750970856",
"seller": "Ruoyi Studio"
},
"options": ["Color", "Size"],
"variants_count": 6,
"price_range": {
"min": { "amount": "49.99", "currency": "USD" },
"max": { "amount": "54.99", "currency": "USD" }
},
"cost_range": {
"min": { "amount": "38.00", "currency": "CNY" },
"max": { "amount": "42.00", "currency": "CNY" }
},
"channels": [
{
"channel": "shopify",
"shop": "acme-goods.myshopify.com",
"external_id": "gid://shopify/Product/8812042",
"status": "draft",
"pushed_at": "2026-11-04T09:20:03Z"
}
],
"sync": {
"rule": "rule_default",
"last_checked_at": "2026-11-04T09:12:40Z"
},
"import": "imp_2c9d",
"created_at": "2026-11-04T09:20:01Z",
"updated_at": "2026-11-04T09:20:03Z"
}List products
GET/v1/products
Your products, newest first.
Scopeproducts:read
Query parameters
statusstring- Optional. active or paused.
channelstring- Optional. shopify, for the ones listed there.
changed_sincestring- Optional. A time: only products whose cost or stock moved since.
limit, cursor- Pagination
curl "https://www.ninjabuy.com/api/v1/products?status=active&limit=2" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"HTTP/2 200 OK
{
"data": [
{
"id": "prd_8f2k",
"title": "Heavyweight Washed Hoodie",
"status": "active",
"variants_count": 6
},
{
"id": "prd_1x0a",
"title": "Canvas Tote",
"status": "active",
"variants_count": 3
}
],
"has_more": true,
"cursor": "c_1x0a"
}Retrieve a product
GET/v1/products/{id}
One product with its source, channels and sync state. Its variants are on their own route.
Scopeproducts:read
Path parameters
idstringrequired- The product's id.
Errors
| Status | Type | When |
|---|---|---|
| 404 | not-found | No such product on this account. |
curl "https://www.ninjabuy.com/api/v1/products/prd_8f2k" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"HTTP/2 200 OK
{
"id": "prd_8f2k",
"title": "Heavyweight Washed Hoodie",
"status": "active",
"source": {
"marketplace": "weidian",
"url": "https://weidian.com/item.html?itemID=7750970856",
"seller": "Ruoyi Studio"
},
"options": ["Color", "Size"],
"variants_count": 6,
"price_range": {
"min": { "amount": "49.99", "currency": "USD" },
"max": { "amount": "54.99", "currency": "USD" }
},
"cost_range": {
"min": { "amount": "38.00", "currency": "CNY" },
"max": { "amount": "42.00", "currency": "CNY" }
},
"channels": [
{
"channel": "shopify",
"shop": "acme-goods.myshopify.com",
"external_id": "gid://shopify/Product/8812042",
"status": "draft",
"pushed_at": "2026-11-04T09:20:03Z"
}
],
"sync": {
"rule": "rule_default",
"last_checked_at": "2026-11-04T09:12:40Z"
},
"import": "imp_2c9d",
"created_at": "2026-11-04T09:20:01Z",
"updated_at": "2026-11-04T09:20:03Z"
}Update a product
PATCH/v1/products/{id}
Change the title or description, or pause and resume it. Send only what changes. Prices are per variant (Variants); a pushed product carries the change to your store on its next push.
Scopeproducts:write
Path parameters
idstringrequired- The product's id.
Body
titlestring- Optional.
descriptionstring- Optional. HTML your store shows.
statusstring- Optional. active or paused. Paused sets stock to 0 on your channels.
sync_rulestring- Optional. A sync rule id; the default rule when null.
Errors
| Status | Type | When |
|---|---|---|
| 404 | not-found | No such product on this account. |
curl -X PATCH "https://www.ninjabuy.com/api/v1/products/prd_8f2k" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11" \
-H "Content-Type: application/json" \
-d '{ "status": "paused" }'HTTP/2 200 OK
{
"id": "prd_8f2k",
"title": "Heavyweight Washed Hoodie",
"status": "paused",
"source": {
"marketplace": "weidian",
"url": "https://weidian.com/item.html?itemID=7750970856",
"seller": "Ruoyi Studio"
},
"options": ["Color", "Size"],
"variants_count": 6,
"price_range": {
"min": { "amount": "49.99", "currency": "USD" },
"max": { "amount": "54.99", "currency": "USD" }
},
"cost_range": {
"min": { "amount": "38.00", "currency": "CNY" },
"max": { "amount": "42.00", "currency": "CNY" }
},
"channels": [
{
"channel": "shopify",
"shop": "acme-goods.myshopify.com",
"external_id": "gid://shopify/Product/8812042",
"status": "draft",
"pushed_at": "2026-11-04T09:20:03Z"
}
],
"sync": {
"rule": "rule_default",
"last_checked_at": "2026-11-04T09:12:40Z"
},
"import": "imp_2c9d",
"created_at": "2026-11-04T09:20:01Z",
"updated_at": "2026-11-04T09:20:03Z"
}Push to Shopify
POST/v1/products/{id}/push
Lists the product on your linked Shopify store: one Shopify product, a variant per SKU you kept, its photos, each variant stocked at the Fulfilled by NinjaBuy location, so the orders for it come to us.
- The first push creates it as a draft: the title and photos came from a Chinese marketplace, so read them before your buyers do, then publish in Shopify.
- Pushing again updates the same Shopify product: prices and stock are set again, variants you dropped are removed. Status, title, description and photos stay as you left them in Shopify unless you send new ones.
- Stock is the seller's count, capped at 100: we buy on demand, so it is how many orders Shopify takes before it shows sold out.
- Your store must sell in US$, since that is what the prices are in. Sold-out variants are skipped and named in skipped[].
Scopeproducts:write
Path parameters
idstringrequired- The product's id.
Body
shopstring- Which linked store, as acme-goods.myshopify.com. Needed only when you linked several.
title, descriptionstring- Optional. Sent to Shopify only when you send them.
Errors
| Status | Type | When |
|---|---|---|
| 409 | no-linked-store | No Shopify store is linked to this account, or several are and shop is missing. |
| 409 | store-not-ready | The store's access lapsed, or our location is not set up yet: open the NinjaBuy app in Shopify once. |
| 422 | store-currency | The store does not sell in US$. |
| 422 | too-many-options | The listing has more than three options; Shopify takes three. |
| 422 | unprocessable | Every variant is sold out, or Shopify refused a field; detail passes its words on. |
curl -X POST "https://www.ninjabuy.com/api/v1/products/prd_8f2k/push" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "shop": "acme-goods.myshopify.com" }'HTTP/2 200 OK
{
"channel": "shopify",
"shop": "acme-goods.myshopify.com",
"external_id": "gid://shopify/Product/8812042",
"status": "draft",
"created": true,
"variants": 5,
"skipped": [{ "sku": "5187209555", "reason": "sold_out" }],
"admin_url": "https://admin.shopify.com/store/acme-goods/products/8812042"
}Delete a product
DELETE/v1/products/{id}
Stops syncing it and sets its stock to 0 on your channels; the Shopify product stays for you to archive. Orders already placed still ship.
Scopeproducts:write
Path parameters
idstringrequired- The product's id.
Errors
| Status | Type | When |
|---|---|---|
| 404 | not-found | No such product on this account. |
curl -X DELETE "https://www.ninjabuy.com/api/v1/products/prd_8f2k" \
-H "Authorization: Bearer $NINJABUY_API_KEY" \
-H "NinjaBuy-Version: 2026-11"HTTP/2 200 OK
{ "id": "prd_8f2k", "deleted": true }