Products
List products
Get a paginated list of products for the current merchant. Requires a merchant scope; a service provider scope is optional, and a request without a merchant scope returns a 422. Returns product details only — use the stock endpoints for quantities. Deleted products are excluded.
Optional attributes
- Name
q- Type
- string
- Description
- Search language filter. Supported fields: `uuid` (uuid), `merchant_sku` (string), `title` (string). Substring matches require at least 3 characters. Clauses can be combined with `AND` / `OR`. Example: `title~"widget" AND merchant_sku:"WIDGET-001"`
- Name
sorts- Type
- array<Sort>
- Description
- Sort the results. Sorting by stock quantities is not supported here — products and stock are separate resources. Example: `sorts[0][field]=title&sorts[0][order]=1`
- Name
expand- Type
- array<string>
- Description
- Relations to include in each product. Omitted relations are absent from the response rather than null. Any other value is rejected with a 422. Example: `expand[]=identifiers&expand[]=tags`
- Name
page- Type
- integer
- Description
- The page number to retrieve (1-indexed) 1
- Name
per_page- Type
- integer
- Description
- The number of products per page 25
Request
curl -G https://YOUR_DOMAIN/api/products \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Create a product
Create a product for the current merchant. Requires a merchant scope; a service provider scope is optional, and a request without a merchant scope returns a 422. `merchant_sku` must be unique among the merchant's products that have not been deleted, so a SKU freed up by deleting a product can be reused.
Required attributes
- Name
merchant_sku- Type
- string
- Description
- The merchant's own Stock Keeping Unit identifier. Must be unique among the merchant's products. WIDGET-001
- Name
title- Type
- string
- Description
- The title or name of the product Blue Widget
Optional attributes
- Name
dimensions- Type
- object
- Description
- The measurements of the product, written as a single field. All three measurements and the unit must be sent together; sending `null` clears all three. Each measurement must convert to between 1 and 500000 millimetres, and is rounded to the nearest millimetre when stored.
- Name
weight- Type
- object
- Description
- The weight of the product, written as a single field. The value and the unit must be sent together; sending `null` clears the weight. The value must convert to between 1 and 500000 grams, and is rounded to the nearest gram when stored.
Request
curl -X POST https://YOUR_DOMAIN/api/products \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"merchant_sku": "WIDGET-001",
"title": "Blue Widget",
"dimensions": {
"length": 150,
"width": 100,
"height": 50,
"unit": "mm"
},
"weight": {
"value": 500,
"unit": "g"
}
}'Get a product
Get a single product by its UUID, including its images, identifiers and tags. Requires a merchant scope; a service provider scope is optional, and a request without a merchant scope returns a 422. Returns product details only — use the stock endpoints for quantities. Deleted products are returned with `is_deleted` set to true.
Required attributes
- Name
product_uuid- Type
- string
- Description
- The UUID of the product
Request
curl -G https://YOUR_DOMAIN/api/products/{product-uuid} \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"Update a product
Update a product's details. Requires a merchant scope; a service provider scope is optional, and a request without a merchant scope returns a 422. Only the properties present in the request body are changed; omitted properties are left as they are. A property sent as `null` is cleared. `dimensions` and `weight` are each written as a whole: their measurements and the unit must be sent together, and sending one as `null` clears it. When the product has `are_dimensions_locked` set, sending `dimensions` or `weight` returns a 422. Deleted products cannot be updated and return a 404.
Required attributes
- Name
product_uuid- Type
- string
- Description
- The UUID of the product
Optional attributes
- Name
title- Type
- string
- Description
- The title or name of the product Blue Widget
- Name
dimensions- Type
- object
- Description
- The measurements of the product, written as a single field. All three measurements and the unit must be sent together; sending `null` clears all three. Each measurement must convert to between 1 and 500000 millimetres, and is rounded to the nearest millimetre when stored.
- Name
weight- Type
- object
- Description
- The weight of the product, written as a single field. The value and the unit must be sent together; sending `null` clears the weight. The value must convert to between 1 and 500000 grams, and is rounded to the nearest gram when stored.
Request
curl -X PUT https://YOUR_DOMAIN/api/products/{product-uuid} \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"title": "Blue Widget",
"dimensions": {
"length": 150,
"width": 100,
"height": 50,
"unit": "mm"
},
"weight": {
"value": 500,
"unit": "g"
}
}'Delete a product
Delete a product. Requires a merchant scope; a service provider scope is optional, and a request without a merchant scope returns a 422. The product is soft deleted: it disappears from the list endpoint, is still readable on the detail endpoint with `is_deleted` set to true, and frees its `merchant_sku` for reuse. Deleting a product that already has stock history requires the `products:delete_with_history` privilege and otherwise returns a 403. Deleting an already deleted product returns a 404.
Required attributes
- Name
product_uuid- Type
- string
- Description
- The UUID of the product
Request
curl -X DELETE https://YOUR_DOMAIN/api/products/{product-uuid} \
-H "Authorization: Bearer {token}" \
-H "Accept: application/json"