Products, modifier groups, option groups, prices, allergens, deals. Read the whole catalogue, mutate what you need, let the platform propagate changes to every channel within seconds.
One price change here. Live on the website, the kiosk, the POS and every aggregator within seconds.
A product is a menu item. A modifier group attaches to it (sauces, sides, crust). An option group sits inside a modifier (extra cheese, no onions). Prices attach per variant, per occasion. Allergens attach per product. Deals compose products into offers.
Returns the full composed menu — products, variants, prices by occasion, modifiers, option groups, allergens and deals — as it will appear to a customer ordering at that location. Supports ETags for cheap polling.
GET /organizations/{organizationId}/menus/locations/{locationId}
Authorization: Bearer <access_token>
If-None-Match: "d41d8cd98f00b204e9800998ecf8427e"
Response — 200 OK (or 304 Not Modified)
{
"locationId": "7f2b6c9e-1a4d-4f12-9b23-5c8e0d1a3b42",
"etag": "3fa5c9b2e1d74d56b82a9f0ed1c4b711",
"categories": [
{
"name": "Pizza",
"products": [
{
"id": "a1c23f44-...",
"name": "Margherita",
"variants": [
{ "name": "Regular", "delivery": 9.50, "collection": 8.50 },
{ "name": "Large", "delivery": 14.50, "collection": 13.50 }
],
"allergens": ["Cereals", "Milk"]
}
]
}
]
}
One endpoint whether you're adding a main, a side, a dessert or a drink — the classification is done via productGroupId. The response returns a GUID; follow up with pricing, allergens and availability calls.
POST /organizations/{organizationId}/products
Authorization: Bearer <access_token>
Content-Type: application/json
{
"name": "Garlic Bread",
"description": "Fresh-baked flatbread, garlic butter, parsley",
"productGroupId": "b5c7a0f4-3e2a-4c1d-8e11-2a9f4bd31c27",
"sku": "SIDE-GARLIC-01"
}
Response — 202 Accepted
{
"id": "8f1d2a74-9c3e-4a6b-b0ff-2e5c741a8d93",
"status": "Queued"
}
Price per variant (Regular, Large), per occasion (Delivery, Collection, DineIn, Counter). Tax rate per price. One call replaces the entire pricing matrix for the product — no partial updates to reason about.
PUT /organizations/{organizationId}/products/{productId}/pricing
Authorization: Bearer <access_token>
Content-Type: application/json
{
"variants": [
{
"name": "Regular",
"prices": [
{ "occasion": "Delivery", "price": 9.50, "taxRate": 0.20 },
{ "occasion": "Collection", "price": 8.50, "taxRate": 0.20 },
{ "occasion": "DineIn", "price": 9.00, "taxRate": 0.20 }
]
},
{
"name": "Large",
"prices": [
{ "occasion": "Delivery", "price": 14.50, "taxRate": 0.20 },
{ "occasion": "Collection", "price": 13.50, "taxRate": 0.20 }
]
}
]
}
Every allergen declaration is either Contains or MayContain, with an optional free-text note. Allergen data flows through to the consumer website, kiosk, receipts and every aggregator menu export.
PUT /organizations/{organizationId}/products/{productId}/allergens
Authorization: Bearer <access_token>
Content-Type: application/json
{
"allergens": [
{ "allergen": "Cereals", "assertion": "Contains", "note": "Wheat flour" },
{ "allergen": "Milk", "assertion": "Contains" },
{ "allergen": "Sesame", "assertion": "MayContain", "note": "Shared prep area" }
]
}
Supported allergens (UK FSA 14)
// Celery, Cereals, Crustaceans, Egg, Fish, Lupins, Milk,
// Molluscs, Mustard, Nuts, Peanuts, Sesame, Soya, Sulphites
A modifier group (e.g. "Pizza toppings") holds a set of option groups (e.g. "Meats", "Veggies"). Attach the group to any product that needs it — change it once, it updates everywhere.
POST /organizations/{organizationId}/modifiergroups
Authorization: Bearer <access_token>
Content-Type: application/json
{
"name": "Pizza Toppings",
"minSelections": 0,
"maxSelections": 8,
"optionGroups": [
{ "optionGroupId": "c1a2-meats-...", "displayOrder": 1 },
{ "optionGroupId": "c1a2-veggies-...", "displayOrder": 2 },
{ "optionGroupId": "c1a2-cheese-...", "displayOrder": 3 }
]
}
The API has no "upload a CSV" endpoint — you integrate your tools directly. List products, filter in your code, issue pricing updates in parallel. Tens of thousands of prices roll out in a few minutes.
GET /organizations/{organizationId}/products?page=1&pageSize=500
Authorization: Bearer <access_token>
Step 2 — for each, PUT the new price
// Loop client-side. Respect rate limits (standard limits suit
// every integration we've seen). 202 Accepted is your signal to
// move on — propagation is asynchronous, never block on it.
PUT /organizations/{organizationId}/products/{id}/pricing
PUT /organizations/{organizationId}/products/{id}/pricing
PUT /organizations/{organizationId}/products/{id}/pricing
// ... carry on until the batch is done.
Need to sync the whole menu into a group's internal catalogue system? Talk to us about menu versioning and snapshot exports.
OAuth2, environments, first read, first write, error handling.
Live orders, history, lifecycle, refunds and receipts.
Customer profiles, tier progress, marketing segments, vouchers.
Metrics, intraday, sales-by-channel/hour/product, BI export.
Webhooks, external stores, courier providers, payment devices.
The full developer platform page, with headline examples.
That's exactly what the menu API is for. Tell us what you're syncing from and we'll send credentials plus a technical contact.
Talk to our team