Catalogue
The catalogue surface is the write half of Mercnet Reports: manage a merchant’s items, categories and menus directly — for inventory tools, price managers and catalogue back offices that are not a POS.
The model is the same one used across the platform — menus contain
categories, categories contain items, items may carry variants and modifier
groups — and everything is keyed on your external_id. If a POS also
syncs this merchant through
Online Ordering menu push,
external ids are scoped per app, so the two integrations do not collide.
| Resource | Endpoints |
|---|---|
| Items | GET/POST /catalogue/items, GET/PATCH/DELETE /catalogue/items/{itemId} |
| Categories | GET/POST /catalogue/categories, GET/PATCH/DELETE /catalogue/categories/{categoryId} |
| Menus | GET/POST /catalogue/menus, GET/PATCH/DELETE /catalogue/menus/{menuId} |
The path parameter on detail routes is the platform’s opaque id — e.g. the
item_id (itm_aa11e0b2c9d4) returned by POST /catalogue/items — not your
external_id, so store the returned id alongside your own when you create a
record.
All writes accept the shared store_id query parameter; item fields match
the menu model — external_id, name, price required, plus
description, image_url, available, categories[], variant_type,
variants[] and the rest.
curl -s "https://api.quiqqy.ai/api/v2/catalogue/items?store_id=st_8fk2c1p9" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "external_id": "SKU-FOCACCIA", "name": "Rosemary Focaccia", "price": 650, "categories": ["cat-sides"], "available": true }'await fetch('https://api.quiqqy.ai/api/v2/catalogue/items?store_id=st_8fk2c1p9', { method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ external_id: 'SKU-FOCACCIA', name: 'Rosemary Focaccia', price: 650, categories: ['cat-sides'], available: true, }),});import requests
requests.post( "https://api.quiqqy.ai/api/v2/catalogue/items", headers={"Authorization": f"Bearer {access_token}"}, params={"store_id": "st_8fk2c1p9"}, json={ "external_id": "SKU-FOCACCIA", "name": "Rosemary Focaccia", "price": 650, "categories": ["cat-sides"], "available": True, },)Creates are idempotent on external_id: posting an id that exists updates it.
Deletes deactivate rather than destroy — the item disappears from sale but
historical reports keep referencing
it.
Availability and price updates
Section titled “Availability and price updates”The two highest-frequency writes have dedicated batch endpoints so a stock sweep or price change is one call, not hundreds:
POST /catalogue/items/availability{ "store_id": "st_8fk2c1p9", "items": [ { "external_id": "SKU-BURRATA", "available": false, "snooze_until": "2026-07-31T04:00:00Z" }, { "external_id": "SKU-FOCACCIA", "available": true } ]}POST /catalogue/items/prices{ "store_id": "st_8fk2c1p9", "items": [ { "external_id": "SKU-MARG", "price": 1399 }, { "external_id": "SKU-MARG-LG", "price": 1799 } ]}Prices are integers in the currency’s minor unit. Variant prices are
addressed by the variant’s own external_id. snooze_until behaves exactly
as in
Online Ordering availability:
the item comes back automatically at the given time.
How changes propagate
Section titled “How changes propagate”A catalogue write lands everywhere the merchant sells, without further calls from you:
- Storefronts — the merchant’s own Quiqqy storefront reflects the change within seconds; a Hub community mirroring the store picks it up on its next catalogue sync (typically under a minute).
- Orders — the next order is priced against the new state; in-flight orders keep the prices they were placed with.
- Webhooks — integrations subscribed to the store receive
menu.updatedfor structural and price changes andmenu.item_availability_changedfor availability flips, so a connected POS can mirror your edits.