One menu per location
Each location has exactly one menu. There’s no concept of multiple named menus (a separate “breakfast menu” and “dinner menu”) for a location — time-of-day differences are expressed within the single menu using availability windows. Publishing replaces that one menu as a whole (applied as a diff — see below). Maple keeps version history internally and always serves the current version, but from your side the model is simple: one location, one menu, which you publish in full.If your own system models several menus per location, flatten them into one Maple menu before publishing — typically
as separate categories with their own availability windows.
The tree
A menu is a tree of three nested objects, with shared definitions referenced from inside it:- Category — a menu section (Drinks, Mains). Can be dayparted so it only appears in certain windows.
- Item — a product. Has one or more variations and may carry modifier groups, tax, and fees.
- Variation — a buyable form of an item (Small / Large, or just “Regular”). The price lives here. Every item has at least one.
- Modifier group — a set of choices (Milk, Toppings) with selection rules. Defined once and shared, or inline on an item. Options can themselves carry nested modifier groups.
Mapping your own catalog
Most integrators already have a menu model. Here’s how typical concepts map — getting this right up front avoids the most common mistakes:| Your concept | Maps to | Notes |
|---|---|---|
| Menu section / heading | Category | Order matters; categories can be dayparted. |
| Product / dish | Item | A name and description; not where the price lives. |
| Size / option that changes the base price (Small/Large) | Variation of the item | Not a separate item. Every item needs ≥1 variation, even if it’s just “Regular”. |
| Add-on / customization (extra shot, no onions) | Modifier option in a modifier group | Group carries the selection rules; option carries any price change. |
| A reusable choice set used on many items (Milk) | Shared modifier group referenced by groupId | Define once, reference everywhere. |
| Combo / build-your-own with sub-choices | Nested modifier groups | Options can carry their own modifier groups. |
External IDs are yours
Every object — category, item, variation, modifier group, option, tax rate, fee — carries anexternalId that you assign and own. Maple never changes it. This is the backbone of the model:
- Re-publishing with the same
externalIdupdates the same object instead of creating a duplicate. - Order line items reference the menu by these IDs (
menu_entity_id), so an incoming order maps directly back to your catalog. - Maple also mints its own IDs (
item_…,var_…,ctg_…) in responses for reference, but you address everything by yourexternalId. - Objects reference each other by
externalIdtoo. When a modifier group reference usesgroupId, an item points at a tax rate withtaxRateIds, or a promotion names its discount withdiscountId, those values are theexternalIds you assigned — not Maple’s minted IDs.
Pricing
Prices are objects, not bare numbers, so the model can express more than a flat amount. The base shape is an amount in integer minor units with a currency:fixed, variable open-amount, per_unit for weighed items, bulk quantity tiers), tax-inclusive pricing, per-currency overrides, and a compare-at (strikethrough) amount. For the common case — a fixed price in one currency — you only need amount. See Money and amounts.
Modifiers
A modifier group has selection rules and a set of options. The rules are richer than a simple min/max, which is what lets you express things like “choose up to 3, but no more than 2 of the same”:| Field | Controls |
|---|---|
minSelections / maxSelections | Total selections allowed (counting quantities). |
minUniqueSelections / maxUniqueSelections | How many distinct options may be chosen. |
freeSelectionCount | How many selections are free before charges apply. |
allowedQuantities | Permitted per-option quantities. |
option minQuantity / maxQuantity | Bounds on a single option. |
groupId, or define one inline. The two shapes are mutually exclusive in a single entry — a reference carries only groupId; a definition carries name and options. Mixing them is rejected rather than silently truncated. Options can carry their own nested modifier groups for build-your-own flows. See Menu recipes for worked examples.
Order resources currently expose the directly-selected, first-level modifiers on each line item. Deeper nested
selections aren’t expanded into the order resource yet.
Tax and fees
These are top-level definitions you attach to items by ID:- Tax categories and rates — rates can be
percentage,flat, orbracket-based, on a configurable base, inclusive or exclusive. Attach withtaxCategoryId/taxRateIds. - Fees — surcharges and deposits (a bottle deposit or CRV), attached with
feeIds. - Discounts, promotions, and coupons — optional top-level collections for price reductions.
Availability and dayparting
Availability windows are how you express time-of-day menus — this replaces the idea of multiple menus.- A category with an availability window only appears during it (breakfast until 11:00).
- An item can carry its own windows too.
- An object with no availability is always available.
dayOfWeek—0(Sunday) through6(Saturday). Add one window per active day.startTime/endTime— localHH:MM, 24-hour.
timezone field (IANA, e.g. America/New_York). It defaults to UTC if unset, so set it on your first publish — see Set the timezone for availability.
A “daily special” or breakfast section is a category (or item) with the right windows, living in the one menu. See the daily-specials recipe.
Stock status
Stock status isin_stock, out_of_stock, or low_stock. On publish, omitting it preserves the current value; brand-new objects default to in_stock. Use it to 86 an item without republishing the whole menu’s structure.
Publishing replaces the whole menu
You always send the entire menu as the desired state. Maple applies it as a diff keyed byexternalId:
- Validation is all-or-nothing — a
400lists every issue and changes nothing. - An identical re-publish is a no-op, and object identities stay stable, so you can publish on every menu change without churn.