PovitoDevelopers

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
json
{
  "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:

  • limit counts products. Each product carries all of your variants of it, so a product never appears on two pages.
  • The status filter is applied in the same query that cuts the page. A filtered page holds limit products whenever more exist. Still page until has_more is false, 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 with 400 validation_error; start again from the first page.

Other fields:

  • There is no updated_since filter. To catch up after downtime, re-pull from the first page.
  • price is your list price. sale_price and campaign_label are set while a Povito markdown campaign runs on that variant. price stays the list price during the campaign.
  • stocked_quantity is 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: true marks a Povito catalog product. Its title, description, categories and brand cannot be changed through this API.
  • handling is a courier handling hint: none, fragile, sealed or cold.

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.

json
{
  "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" }
  ]
}
json
{
  "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, description and category_ids are applied; category_ids replaces the product's categories. price_iqd and initial_stock are ignored. Set price and stock with PATCH /inventory/bulk. An update row for a published product moves it back to proposed for review, even if nothing changed. Leave unchanged products out of the request. A catalog-managed product rejects the row with catalog_product_locked.
  • The SKU is new: create. title and price_iqd are required. The product is created as draft, with a single Default variant 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 rejected row inside a 200, never a 400 for the whole request. That includes a row that is not an object or whose external_sku is 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 without title or price_iqd, a category that accepts only Povito catalog products (catalog_only_category), or a locked catalog product. Always read results[].
  • A top-level 400 validation_error means items itself 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:

  1. POST /products/bulk creates it as draft. It stays a draft until it is submitted.
  2. Someone on your team submits it for approval in the Seller dashboard. It moves to proposed.
  3. Povito reviews it. If approved, it becomes published. If refused, it becomes rejected with a rejection_reason, and can be submitted again from the dashboard.

Track where a product is with GET /products?status=… or GET /products/{sku}.