Zernio
APIFor you
Zernio
APIFor you
Platforms

Shopify

Overview

Set up

Connect

Publish

Blog Articles

Commerce

Commerce & ProductsTracking Pixels

Reference

Limits & Errors
Dashboard
OverviewPlatformsAPI ReferenceResources
Shopify

Commerce & Products

Manage a Shopify store's catalog through the Commerce API and the deprecated Products API.


Commerce

A connected store is a Commerce store. Pass this account's id as accountId to the Commerce API at /v1/commerce.

It creates and edits products, variants, images, stock, collections, discounts, sales channel publishing, market prices, metafields, metaobjects, pages, menus, redirects and marketing activities. It can also sync the store into a Meta catalog for catalog ads.

Products, collections, metafields and pages work on every install.

Stock, sales channels, discounts, navigation, metaobjects, markets, marketing activities and image removal need optional scopes.

GET /v1/commerce/store lists them in missingCapabilities and returns grantPermissionsUrl, where the merchant approves them without reinstalling. See Capabilities and extra permissions.

curl "https://zernio.com/api/v1/commerce/store?accountId=66b2e19d8c3f5a7e9d0b1c2d" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Products

The Products API below is deprecated in favor of the Commerce API, which returns the same catalog in the platform-neutral shape.

It keeps working for existing integrations. List and read products with their variants, options and images, and edit a product's own fields and variant prices.

All data lives on Shopify. Zernio proxies it and stores nothing.

List products

Call GET /v1/accounts/{accountId}/products. Filter with status (active, draft or archived) and query, Shopify's product search syntax, which is passed through verbatim:

const { data: page } = await zernio.products.listProducts({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' },
  query: { status: 'active', query: 'vendor:Acme tag:summer', limit: 20 }
});

for (const product of page.products) {
  console.log(product.id, product.title, product.variants[0]?.price);
}

Response (200):

{
  "platform": "shopify",
  "products": [
    {
      "id": "8214569812345",
      "platform": "shopify",
      "title": "Linen shirt",
      "handle": "linen-shirt",
      "descriptionHtml": "<p>Breathable linen for warm days.</p>",
      "vendor": "Acme",
      "productType": "Shirts",
      "tags": ["summer", "linen"],
      "status": "active",
      "featuredImage": { "url": "https://cdn.shopify.com/s/files/1/.../linen-front.jpg", "altText": "Linen shirt, front" },
      "images": [{ "url": "https://cdn.shopify.com/s/files/1/.../linen-front.jpg", "altText": "Linen shirt, front" }],
      "options": [{ "name": "Size", "values": ["S", "M", "L"] }],
      "variants": [
        {
          "id": "45123456789012",
          "title": "S",
          "sku": "LINEN-S",
          "barcode": null,
          "price": "59.00",
          "compareAtPrice": "79.00",
          "inventoryQuantity": 12,
          "availableForSale": true,
          "selectedOptions": [{ "name": "Size", "value": "S" }]
        }
      ],
      "seo": { "title": "Linen shirt | Acme", "description": null },
      "totalInventory": 31,
      "onlineStoreUrl": "https://acme.com/products/linen-shirt",
      "createdAt": "2026-05-02T10:12:00Z",
      "updatedAt": "2026-09-01T08:30:00Z",
      "publishedAt": "2026-05-02T10:15:00Z"
    }
  ],
  "nextCursor": "eyJsYXN0X2lkIjo4MjE0NTY5ODEyMzQ1fQ=="
}

Pagination is the same cursor scheme as the Blogs API: limit 1 to 50 (default 20) and nextCursor, null on the last page.

The response carries the first 100 variants and the first 20 images of each product.

Update a product

Call PATCH /v1/accounts/{accountId}/products/{productId} with any subset of title, descriptionHtml, handle, vendor, productType, tags, status, seo and variants.

  • tags replaces the whole list.
  • variants changes the price and compare-at price of the listed variant ids only. A variant that belongs to another product is a 400.

The response is the product as it reads after the update.

const { data: updated } = await zernio.products.updateProduct({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d', productId: '8214569812345' },
  body: {
    descriptionHtml: '<p>Breathable linen for warm days. Now in three sizes.</p>',
    tags: ['summer', 'linen', 'new'],
    seo: { title: 'Linen shirt | Acme', description: 'A breathable linen shirt in S, M and L.' },
    variants: [{ id: '45123456789012', price: 54.0, compareAtPrice: 79.0 }]
  }
});

console.log(updated.product.variants[0].price); // "54.00"

Prices are decimal strings in the store currency. A number is accepted and formatted to two decimals.

Send "compareAtPrice": null to take a variant off sale.

status: "draft" unpublishes a product without deleting it, and status: "archived" hides it everywhere. Both are reversible with status: "active".

Every product operation

OperationEndpoint
List productsGET /v1/accounts/{accountId}/products
Get a productGET /v1/accounts/{accountId}/products/{productId}
Update a productPATCH /v1/accounts/{accountId}/products/{productId}
Was this page helpful?

Blog Articles

Create, draft, schedule and update the blog articles of a Shopify store, and the article fields they accept.

Tracking Pixels

Install ad platform pixels on a Shopify store's storefront and checkout with one call.

On this page

CommerceProductsList productsUpdate a productEvery product operation