Quickstart

Five minutes from a fresh API key to reading your catalog. All you need is curl (and optionally jq).

1 · Create a key and verify it

Create a key with the pim:read scope in Settings → API, export it, and ping:

export PEAK_PIM_KEY="pk_live_..."

curl https://app.peak-pim.com/api/v1/ping \
  -H "Authorization: Bearer $PEAK_PIM_KEY"
{"status":"ok","account_id_present":true}

A 200 here proves the key end to end — authentication, route allowlist, scope, and rate limiter. Anything else: see Errors & limits.

2 · List your stores

curl "https://app.peak-pim.com/api/v1/stores" \
  -H "Authorization: Bearer $PEAK_PIM_KEY"
{
  "data": [
    { "id": "1e8e…", "domain": "acme.myshopify.com", "name": "Acme US" },
    { "id": "9c1f…", "domain": "acme-eu.myshopify.com", "name": "Acme EU" }
  ],
  "next_cursor": null
}

Keep a store id around — you'll use it in step 5.

3 · List products

curl "https://app.peak-pim.com/api/v1/products?limit=5" \
  -H "Authorization: Bearer $PEAK_PIM_KEY"
{
  "data": [
    {
      "id": "7b2a…",
      "type": "product",
      "title": "Trail Runner 2",
      "draft_revision": 14,
      "pending_publish": true,
      "last_publish_status": "published",
      "store_ids": ["1e8e…", "9c1f…"]
    }
  ],
  "next_cursor": "eyJv…"
}

To walk the whole catalog, pass next_cursor back as cursor until it comes back null:

curl "https://app.peak-pim.com/api/v1/products?limit=250&cursor=eyJv..." \
  -H "Authorization: Bearer $PEAK_PIM_KEY"

Useful filters (combinable): search=trail, status=pending, updated_since=2026-07-01T00:00:00Z.

4 · Read one product

curl "https://app.peak-pim.com/api/v1/products/7b2a..." \
  -H "Authorization: Bearer $PEAK_PIM_KEY"
{
  "id": "7b2a…",
  "type": "product",
  "title": "Trail Runner 2",
  "attributes": [
    { "key": "title", "value": "Trail Runner 2", "type": "single_line_text" },
    { "key": "vendor", "value": "Acme", "type": "single_line_text" }
  ],
  "draft_revision": 14,
  "pending_publish": true,
  "last_publish_status": "published",
  "variant_ids": ["c410…", "c411…"],
  "media_ids": ["88ab…"],
  "stores": [
    { "store_id": "1e8e…", "store_domain": "acme.myshopify.com",
      "pending_publish": true, "last_publish_status": "published" },
    { "store_id": "9c1f…", "store_domain": "acme-eu.myshopify.com",
      "pending_publish": false, "last_publish_status": "published" }
  ]
}

These are the canonical values every store inherits, plus the publish state per store. The same shape works for /variants/{id}, /collections/{id}, and /media/{id}.

5 · Compare a store's version

curl "https://app.peak-pim.com/api/v1/products/7b2a.../stores/9c1f..." \
  -H "Authorization: Bearer $PEAK_PIM_KEY"
{
  "store_id": "9c1f…",
  "store_domain": "acme-eu.myshopify.com",
  "attributes": [
    { "key": "title", "value": "Trail Runner 2 — EU Edition", "type": "single_line_text" }
  ],
  "pending_publish": false,
  "last_publish_status": "published"
}

This is what that store actually publishes — overrides included. Diff it against the canonical attributes from step 4 to find per-store drift, or use /stores (no store_id) to fetch every store version at once.

6 · Poll efficiently

Two mechanisms keep recurring syncs cheap:

curl -i "https://app.peak-pim.com/api/v1/products/7b2a..." \
  -H "Authorization: Bearer $PEAK_PIM_KEY" \
  -H 'If-None-Match: "W/abc123"'
# HTTP/2 304 — nothing changed, no body transferred

Where to go next