Zikkio

One product row, seven platforms

Every variant comes back as one row with the same ten fields, whether the store runs on Shopify, WooCommerce, Magento 2, PrestaShop, BigCommerce, Wix or Google Merchant Center. What a platform does not have stays empty, and the exceptions are written down here.

GET /v1/connections/{id}/products

At a glance

Row
One per variant, with its product id
Fields
The same ten on all seven platforms
Reads
7 platforms
Price writes
6 platforms
List
From the cache, refreshed every day
Single product
Live from the store

The ten fields

What each field holds, and where a platform does it differently.

Field What it holds Where it differs
sku What it holds: The variant’s SKU, as the merchant typed it. Price updates address rows by SKU. Where it differs: Two rows can share a SKU; Zikkio lists duplicate SKUs instead of merging them.
gtin What it holds: EAN, UPC or ISBN of the variant. Where it differs: Magento 2: read from the attribute you configure. Empty when the store has none.
name What it holds: Product name, with the variant option. Where it differs: Google Merchant Center: the product title.
brand What it holds: The brand, as text. Where it differs: Magento 2: read from the attribute code you configure.
category What it holds: Every category the product sits in, as one path joined with >. Where it differs: Google Merchant Center: empty, products have no categories there.
price What it holds: The selling price, in the store’s currency. Where it differs: Written back on six platforms; Google Merchant Center is read-only.
cost What it holds: What the merchant pays for the item. Where it differs: Empty when the store does not keep a cost.
stock What it holds: Units available. Where it differs: Not tracked on the platform: 1, so the row counts as in stock. Google Merchant Center: 1 or 0.
image What it holds: URL of the main image, served by the platform. Where it differs: Empty when the product has no image.
product_id What it holds: Id of the parent product. GET …/products/{product_id} reads it live with all its variants. Where it differs: A product without variants is one row, with its own id here.

How a row is built

The same steps on every platform, so your code reads one shape.

POST /v1/connections/con_8f2a/catalog/sync
Request
curl -X POST https://api.zikkio.com/v1/connections/con_8f2a/catalog/sync \
  -H "Authorization: Bearer zk_live_••••"
Response 202 Accepted 41 ms
{
  "job_id": "job_9c1e",
  "status": "queued",
  "last_sync": "2026-10-07T06:12:00Z",
  "rows": 12480
}
ZIKKIO one row per variant, the parent id on each
One product, as the store sends it
{
  "name": "Black tee",
  "brand": "Acme",
  "variants": [
    { "sku": "TEE-BLK-M", "price": 29.90, "stock": 42 },
    { "sku": "TEE-BLK-L", "price": 29.90, "stock": 17 }
  ]
}
Rows in the cache not an API call
{ "sku": "TEE-BLK-M", "name": "Black tee · M", "product_id": "prod_41f" }
{ "sku": "TEE-BLK-L", "name": "Black tee · L", "product_id": "prod_41f" }
GET /v1/connections/con_8f2a/products
Request
curl https://api.zikkio.com/v1/connections/con_8f2a/products?limit=1 \
  -H "Authorization: Bearer zk_live_••••"
Response 200 OK 64 ms · from the cache
{
  "data": [
    {
      "sku": "TEE-BLK-M",
      "gtin": "4006381333931",
      "name": "Black tee · M",
      "brand": "Acme",
      "category": "Apparel > Tees",
      "price": 29.90,
      "cost": 11.20,
      "stock": 42,
      "image": "https://cdn.example.com/tee-blk.jpg",
      "product_id": "prod_41f"
    }
  ],
  "next_cursor": "eyJvZmZzZXQiOjF9"
}
GET /v1/connections/con_8f2a/products/prod_41f
Request
curl https://api.zikkio.com/v1/connections/con_8f2a/products/prod_41f \
  -H "Authorization: Bearer zk_live_••••"
Response 200 OK 212 ms · live from the store
{
  "id": "prod_41f",
  "name": "Black tee",
  "brand": "Acme",
  "category": "Apparel / Tees",
  "variants": [
    { "sku": "TEE-BLK-M", "price": 29.90, "cost": 11.20, "stock": 42 },
    { "sku": "TEE-BLK-L", "price": 29.90, "cost": 11.20, "stock": 17 }
  ]
}

How it stays fresh

Reads come from Zikkio’s copy of the catalog, and three things keep that copy right.

Refreshed every day

A full refresh of every connected catalog runs once a day, so list calls answer from the cache and never wait on the store.

Sync on demand

POST /catalog/sync starts a refresh whenever you need one and answers 202 with the job id. When it finishes, the catalog.synced webhook tells your endpoint how many rows were added, removed or repriced.

Truncation guard

An import that would delete more than 90% of a catalog is refused and held for review, so a bad download never empties your cache.

Where platforms differ

The row is the same; how it is filled is not.

Platform Variants Stock and attributes
Shopify Variants: Variants exported with a bulk operation, one row each. Stock and attributes: Inventory the store does not track reads as in stock.
WooCommerce Variants: Variations read page by page, one row each. Stock and attributes: Stock from the managed quantity, or from the stock status when the product does not manage stock.
Magento 2 Variants: Configurable products, one row per child. Stock and attributes: Brand and GTIN come from the attribute codes you configure; store views are read separately.
PrestaShop Variants: Combinations, one row each with its own SKU and price. Stock and attributes: Stock per combination.
BigCommerce Variants: Variants, one row each. Stock and attributes: Products with inventory tracking off read as in stock.
Wix Variants: Products and variants, one row each. Stock and attributes: Same fields as the other platforms.
Google Merchant Center Variants: No variants: every product is one row, product_id equal to its own id. Stock and attributes: Read-only. Stock is 1 for in stock, 0 otherwise; no categories.

Each platform has its own page: Shopify, WooCommerce, Magento 2, PrestaShop, BigCommerce, Wix and Google Merchant Center. Plans and limits are on the pricing page.

Product data questions

What developers ask before they read the first catalog.

Is the product list live or cached?
Cached. Zikkio keeps one row per variant for every connected store and answers list calls from that copy, refreshed every day or on demand with POST /catalog/sync. A single product is read live from the store.
What if two variants share a SKU?
Both rows come through, each with its own product_id. Zikkio also lists the SKUs a store uses more than once, so you can see them before you write prices.
What comes back when a store has no GTIN or cost?
null. A field the platform does not have, or the merchant has not filled in, stays empty; Zikkio never fills it with a guess.
How are categories returned?
As one text path with every category the product belongs to, joined with >. Google Merchant Center products have no categories, so the field is empty there.
How big can a catalog be?
Catalogs with millions of rows come through complete: Shopify bulk operations, resumable page downloads and retries on 429s and deadlocks. Today Zikkio keeps 3.1M variant rows in its cache.
Which fields can I write?
Prices, in bulk, on six of the seven platforms: Google Merchant Center is read-only. Every row you send comes back as applied or failed, with the reason.

Connect your first store today.

Free plan with 5,000 API calls a month and unlimited stores. No card, and no sales call unless you ask for one.

POST /v1/connect/sessions
curl -X POST https://api.zikkio.com/v1/connect/sessions \
  -H "Authorization: Bearer zk_test_••••" \
  -d '{ "platform": "shopify" }'
201 Created
{ "connect_url": "https://connect.zikkio.com/s/ses_3kd9" }