Products#
Read your catalog and create or update products, keyed by your own SKU. Every request goes to your environment's base URL with your key, as in the quickstart. Lists are cursor-paginated, and all money is whole Iraqi dinars.
GET /products#
Pull your catalog, newest product first. Scope catalog:read.
| Query | Type | Notes |
|---|---|---|
status |
string | Keep only products in this status: draft, proposed, published or rejected. An unknown value is not rejected; it matches nothing |
cursor |
string | next_cursor from the previous page; omit for the first page. Anything else is refused with 400 validation_error |
limit |
integer | Products per page; default 20, max 100 |
{
"data": [
{
"id": "prod_01K4R8Z2Q6M3VYB7TD1N5HXJ2C",
"title": "Sony WH-1000XM5 Wireless Headphones",
"handle": "sony-wh-1000xm5-wireless-headphones",
"status": "published",
"description": "Noise-cancelling over-ear headphones, black.",
"thumbnail": "https://cdn.povito.com/static/products/prod_01K4R8Z2Q6M3VYB7TD1N5HXJ2C/1.jpg",
"images": ["https://cdn.povito.com/static/products/prod_01K4R8Z2Q6M3VYB7TD1N5HXJ2C/1.jpg"],
"category_ids": ["pcat_01K3W6H8M2P4R6T8V0X2Z4B6D8"],
"brand": { "id": "brand_01K3Y2A4C6E8G0J2L4N6Q8S0U2", "name": "Sony", "slug": "sony" },
"variants": [
{
"offer_id": "offer_01K4R8Z3A1B2C3D4E5F6G7H8J9",
"variant_id": "variant_01K4R8Z2S8T4W6Y8A0C2E4G6J8",
"sku": "ERP-1042",
"options": { "Default": "Default" },
"price": 425000,
"sale_price": null,
"campaign_label": null,
"stocked_quantity": 12,
"condition": null,
"notes": null
}
],
"catalog_managed": false,
"handling": "none",
"rejection_reason": null,
"created_at": "2026-09-01T10:00:00.000Z",
"updated_at": "2026-09-04T08:12:00.000Z"
}
],
"next_cursor": "prod_01K4R8Z2Q6M3VYB7TD1N5HXJ2C",
"has_more": true
}Pages are cut over your products:
limitcounts products. Each product carries all of your variants of it, so a product never appears on two pages.- The
statusfilter is applied in the same query that cuts the page. A filtered page holdslimitproducts whenever more exist. Still page untilhas_moreisfalse, not on page size. - The order is newest product first, by Povito product id, and stays stable while you page.
- A cursor saved before 11 September 2026, when pages were cut over variants, is an offer id (
offer_…). It is refused with400 validation_error; start again from the first page.
Other fields:
- There is no
updated_sincefilter. To catch up after downtime, re-pull from the first page. priceis your list price.sale_priceandcampaign_labelare set while a Povito markdown campaign runs on that variant.pricestays the list price during the campaign.stocked_quantityis on-hand units summed across all your stock locations, not reduced by reservations. It is always a whole number: a fractional stock level, possible only through writes outside Povito's seller and partner APIs, is rounded to the nearest unit at each location.catalog_managed: truemarks a Povito catalog product. Its title, description, categories and brand cannot be changed through this API.handlingis a courier handling hint:none,fragile,sealedorcold.
Product status#
status |
Meaning |
|---|---|
draft |
Created, not submitted for review. Products created through this API start here |
proposed |
Submitted and awaiting Povito's review |
published |
Approved and live |
rejected |
Refused in review; rejection_reason says why |
GET /products/{sku}#
Look up one product by your own SKU, URL-encoded. Scope catalog:read. Any of the product's variant SKUs returns the same product, with all of its variants. If you have used one SKU on several products, the first match is returned. Returns 404 product_not_found when the SKU matches none of your products.
POST /products/bulk#
Create or update products in one call, keyed by your own SKU. Scope catalog:write. Requires Idempotency-Key: a retry with the same key gets the first response back without running the rows again. Up to 50 rows. Rate limit: 60 requests per 600 seconds per API key, counted separately from PATCH /inventory/bulk. See idempotency and rate limits.
{
"items": [
{
"external_sku": "ERP-1042",
"title": "Sony WH-1000XM5 Wireless Headphones",
"price_iqd": 425000,
"description": "Noise-cancelling over-ear headphones, black.",
"category_ids": ["pcat_01K3W6H8M2P4R6T8V0X2Z4B6D8"],
"initial_stock": 12
},
{ "external_sku": "ERP-1043", "title": "Anker PowerCore 20000 (renamed)" },
{ "external_sku": "ERP-1044", "title": "USB-C cable 2 m" }
]
}{
"results": [
{ "external_sku": "ERP-1042", "status": "accepted", "product_id": "prod_01K4R8Z2Q6M3VYB7TD1N5HXJ2C" },
{ "external_sku": "ERP-1043", "status": "accepted", "product_id": "prod_01K4P1C7E9G3J5L7N9Q1S3U5W7" },
{
"external_sku": "ERP-1044",
"status": "rejected",
"error": { "code": "validation_error", "message": "title and price_iqd are required to create a new SKU." }
}
]
}Each row is matched on external_sku:
- The SKU is already on one of your products: update. Only
title,descriptionandcategory_idsare applied;category_idsreplaces the product's categories.price_iqdandinitial_stockare ignored. Set price and stock withPATCH /inventory/bulk. An update row for apublishedproduct moves it back toproposedfor review, even if nothing changed. Leave unchanged products out of the request. A catalog-managed product rejects the row withcatalog_product_locked. - The SKU is new: create.
titleandprice_iqdare required. The product is created asdraft, with a singleDefaultvariant that carries the SKU and the price.initial_stock(default 0) is placed at your first stock location. A size or colour matrix is built in the Seller dashboard.
Errors:
- Every row problem is a
rejectedrow inside a200, never a400for the whole request. That includes a row that is not an object or whoseexternal_skuis missing or blank: its result has"external_sku": null, and because results are in request order, its position tells you which row it was. Other examples: a create withouttitleorprice_iqd, a category that accepts only Povito catalog products (catalog_only_category), or a locked catalog product. Always readresults[]. - A top-level
400 validation_errormeansitemsitself is missing, empty or over 50 rows. - Any other field of the wrong JSON type is dropped, not rejected.
- Do not repeat a SKU within one request. Rows run concurrently, so two creates for the same new SKU can race.
From draft to live#
Bulk upsert never publishes a product, and the Partner API has no call to submit one for review. A new product goes live in three steps:
POST /products/bulkcreates it asdraft. It stays a draft until it is submitted.- Someone on your team submits it for approval in the Seller dashboard. It moves to
proposed. - Povito reviews it. If approved, it becomes
published. If refused, it becomesrejectedwith arejection_reason, and can be submitted again from the dashboard.
Track where a product is with GET /products?status=… or GET /products/{sku}.