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:
-
updated_since— only entities whose canonical record changed since your last run. Store-local edits don't widen it, so re-read the store versions of entities you track. -
ETags — every 200 carries an
ETag; send it back asIf-None-Matchand unchanged resources answer304with no body.
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
- Full endpoint reference — every parameter and response field.
- Errors & limits — the error envelope, rate limits, and retry behavior.
- MCP connector — the same catalog, as tools for AI assistants.