Catalog

Variants

A variant belongs to exactly one product — its product_id — and, like every entity, its values exist twice: the canonical values every store inherits and one store version per store that can override them. Variants are a top-level list, so a price or inventory integration can walk them without touching products at all.

List variants

GET/api/v1/variantspim:read

One cursor page of the account's variants, ordered oldest change first so a poller can walk the whole catalog and stop when next_cursor is null.

Query parameters

ParameterTypeDescription
limitintegerRows per page. Default 50, maximum 250; a value above the maximum is clamped and a non-numeric value falls back to the default.
cursorstringThe next_cursor of the previous page. Opaque — do not build or parse one. A cursor from a different list is rejected with validation_failed.
updated_sinceRFC3339 date-timeOnly variants whose own canonical record changed at or after this time. Store-version edits do not widen it. A non-RFC3339 value is rejected with validation_failed.
statusenumPublish-state filter: never_published, pending, published, failed.
searchstringFree-text match on the variant's name, SKU, or the parent product's name, title, vendor, or tags.

Response

The same list-item shape as every entity list: id, type (here variant), title, draft_revision, pending_publish, last_publish_status, and store_ids. last_publish_status takes the same values as the status filter, so a response value can be fed straight back in.

# Find a variant by SKU
curl -s "https://api.peak-pim.com/api/v1/variants?search=TR2-BLK-42&limit=50" \
  -H "Authorization: Bearer pk_live_..."
{
  "data": [
    {
      "id": "c7a1d2e3-5b6f-4890-a1b2-c3d4e5f60718",
      "type": "variant",
      "title": "Trail Runner 2 — Black / 42",
      "draft_revision": 6,
      "pending_publish": false,
      "last_publish_status": "published",
      "store_ids": ["9b2f6c1a-7d3e-4f80-b1c5-6a4e8d2b9c30"]
    }
  ],
  "next_cursor": null
}

Get a variant

GET/api/v1/variants/{id}pim:read

One variant's canonical values, the product it belongs to (product_id), its media files, and its per-store publish state. An unknown id — including another account's — answers 404 not_found.

FieldTypeDescription
id, type, titleAs on the list row; type is variant.
attributesarrayThe canonical values every store inherits, as {key, value, type} triples (all strings).
draft_revisionintegerThe optimistic-concurrency handle a later write sends back to prove it read the current state.
pending_publish, last_publish_statusAs on the list row.
product_iduuidThe product this variant belongs to. Fetch it via GET /api/v1/products/{id}.
media_idsuuid[]The media files this variant uses, in gallery order, across every store.
stores[]arrayPublish state per store: store_id, store_domain, pending_publish, last_publish_status. Publish state only — values live on the store subresources below.
{
  "id": "c7a1d2e3-5b6f-4890-a1b2-c3d4e5f60718",
  "type": "variant",
  "title": "Trail Runner 2 — Black / 42",
  "attributes": [
    { "key": "sku", "value": "TR2-BLK-42", "type": "single_line_text_field" },
    { "key": "price", "value": "129.00", "type": "single_line_text_field" }
  ],
  "draft_revision": 6,
  "pending_publish": false,
  "last_publish_status": "published",
  "product_id": "5e0deff8-4b6f-4a24-9d6d-2f8c2f2a9a11",
  "media_ids": ["1f2e3d4c-5b6a-4798-8172-635a4b3c2d1e"],
  "stores": [
    {
      "store_id": "9b2f6c1a-7d3e-4f80-b1c5-6a4e8d2b9c30",
      "store_domain": "acme.myshopify.com",
      "pending_publish": false,
      "last_publish_status": "published"
    }
  ]
}
Variants carry no variant_ids.

variant_ids exists on products only, and product_id on variants only — the relationship is stored once and readable from both ends.

List a variant's store versions

GET/api/v1/variants/{id}/storespim:read

Every store version of the variant. Bounded by the account's stores, so the whole list is returned and next_cursor is always null. Each item carries store_id, store_domain, attributes, pending_publish, and last_publish_status.

{
  "data": [
    {
      "store_id": "9b2f6c1a-7d3e-4f80-b1c5-6a4e8d2b9c30",
      "store_domain": "acme.myshopify.com",
      "attributes": [
        { "key": "price", "value": "119.00", "type": "single_line_text_field" }
      ],
      "pending_publish": false,
      "last_publish_status": "published"
    }
  ],
  "next_cursor": null
}

Get one store's version

GET/api/v1/variants/{id}/stores/{store_id}pim:read

One store's version of the variant: the values that store publishes — a per-store price, for instance — which may differ from every other store's. store_id comes from GET /api/v1/stores. A variant with no version on the requested store answers 404 not_found.

curl -s "https://api.peak-pim.com/api/v1/variants/c7a1d2e3-5b6f-4890-a1b2-c3d4e5f60718/stores/9b2f6c1a-7d3e-4f80-b1c5-6a4e8d2b9c30" \
  -H "Authorization: Bearer pk_live_..."

Subresources

Variants carry two more reads, documented on their own pages:

EndpointReturnsDocs
GET /api/v1/variants/{id}/sales-channels?store_id=…The Shopify sales channels the variant is published to on one store. Reaches Shopify live, so it can answer 502.Sales channels
GET /api/v1/variants/{id}/dropsThe drops that will change this variant, each narrowed to the changes that touch it.Drops