For the complete documentation index, see llms.txt. This page is also available as Markdown.

Catalog API

REST API for native apps to render published menus, sections, products, and customizations.

Use this API when a native app needs to read published catalog data and render its own UI. For storefront JavaScript in the merchant theme, use the Widget API instead.

Catalog API v1 is REST at /api/catalog/v1. GraphQL is not available yet. The API is enabled per store — until it is on, native apps should keep using a WebView of the merchant’s Zapiet ordering page.

A machine-readable OpenAPI 3.1 spec is published in this organization as eats-catalog-v1. Import it into Postman, Insomnia, or your codegen tool from GitBook OpenAPI settings, or from the repo file docs/openapi/catalog-v1.yaml.

Authentication

  1. In Zapiet Eats go to Settings → API credentials.

  2. Create a personal access token. Copy the secret once (it is not shown again).

  3. Send it on every request:

Authorization: Bearer {token}
Accept: application/json

The token is bound to one store. It cannot read another merchant’s menus.

Optional (must match the token’s store if present):

X-Zapiet-Eats-Shop-Url: your-store.myshopify.com

A mismatched shop header returns 403.

Required scope: catalog:read (native apps) or api:* (existing full-access merchant tokens).

  • catalog:read is read-only catalog access. New tokens default to this. It cannot call other Zapiet REST surfaces.

  • api:* is full REST access for the bound store. Do not put api:* in a native app.

Rate limits

  • Default: 40 requests per second per store.

  • Over the limit: 429 { "error": "rate_limited" } with Retry-After.

Errors

HTTP

error

Meaning

401

unauthorized

Missing, expired, revoked, or unbound token

403

forbidden

Shop header does not match the token’s store

403

missing_scope

Valid token without catalog:read or api:*

404

not_found

Unknown id, other store’s id, draft menu, or API not enabled

422

validation_error

Bad query params

429

rate_limited

Too many requests

REST

Base: https://{eats-host}/api/catalog/v1

Prices are integer cents in the shop currency.

Localization

Field
Localized?
Response shape

Menu name

Yes

name + translations

Section name

Yes

name + translations

Section description

No

description string or null

Product name

No (Shopify string)

name only

Allergens / dietary restrictions

Yes

{ id, name, translations }

name is the store default locale (Settings → Languages). translations is a locale → string map. When a menu or section has no localized names, name is "" and translations is {}.

List locations

List published menus

Get a menu tree (slim product cards)

Id or handle (m-1197) both work. Draft menus are omitted.

The menu root and each section include name and translations. Product cards omit body_html, product_options, and Shopify options / option_groups.

Each product card includes:

  • id, name, image_url, price_range (min / max in cents), calories

  • variants[] — variant_id, name, price (cents)

  • has_options — true when published Product Options, more than one variant, or meal-deal / pick-a-side groups exist

  • allergens[] and dietary_restrictions[] as { id, name, translations }

List section metadata (no products)

Get one section (slim product cards)

Use this after the section list when loading a large menu one section at a time.

Get one product (full payload)

Returns body_html, published product_options, Shopify options / option_groups, full variants, and bundle / choice groups. 404 if the product is not on that published menu section.

List allergens and dietary restrictions

Same { id, name, translations } shape. Merchant Settings labels win over Zapiet defaults. Cache these maps.

Loading pattern

  • Small menu: GET /menus/{id}, then nested product URL on tap.

  • Large menu: GET /menus/{id}/sections, then GET /menus/{id}/section/{sectionId} per section; nested product URL on tap.

What v1 does not do

  • Add to cart, checkout, or charge the customer (use Shopify / existing WebView).

  • Return draft menus or draft customizations.

  • Return another store’s data.

  • Replace the App Proxy page for browser customers.

Store the token safely

  • iOS: Keychain. Android: EncryptedSharedPreferences / Keystore.

  • One token per store. Rotate by revoking in Settings → API credentials.

  • Never ship the Shopify app secret, and never log the Bearer token.

Examples

Last updated