> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maple.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# The menu model

> How a Maple menu is structured, how to map your own catalog onto it, and the rules that prevent wrong assumptions.

A menu is the structured description of everything a customer can order at a location: the items, how they're priced, how they're customized, and which taxes and fees apply. You publish it as one JSON document, and Maple keys every object off the **external IDs you assign**. This page explains the model and how to map your own catalog onto it. The [Publish a menu](/developer-api/guides/publish-menu) guide covers the request flow, [Menu recipes](/developer-api/guides/menu-recipes) has worked examples, and the [endpoint reference](/developer-api/api-reference) lists every field.

## 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](#availability-and-dayparting).

Publishing replaces that one menu as a whole (applied as a diff — see [below](#publishing-replaces-the-whole-menu)). 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.**

<Note>
  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.
</Note>

## The tree

A menu is a tree of three nested objects, with shared definitions referenced from inside it:

```mermaid theme={null}
flowchart TD
  Cat[Category] --> Item[Item]
  Item --> Var[Variation · carries the price]
  Item -.modifierGroups.-> MG[Modifier group]
  Var -.modifierGroups.-> MG
  MG --> Opt[Modifier option]
  Opt -.nested.-> MG
  Item -.taxCategoryId / taxRateIds.-> Tax[Tax category & rates]
  Item -.feeIds.-> Fee[Fees]
```

* **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.                                     |

<Warning>
  Common wrong assumptions to avoid: a price does **not** live on the item (it lives on the **variation**); a size is
  **not** a separate item (it's a variation); and there is **one** menu per location (dayparting is availability
  windows, not separate menus).
</Warning>

## External IDs are yours

Every object — category, item, variation, modifier group, option, tax rate, fee — carries an `externalId` that **you** assign and own. Maple never changes it. This is the backbone of the model:

* Re-publishing with the same `externalId` updates 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 your `externalId`.
* **Objects reference each other by `externalId` too.** When a modifier group reference uses `groupId`, an item points at a tax rate with `taxRateIds`, or a promotion names its discount with `discountId`, those values are the `externalId`s you assigned — not Maple's minted IDs.

Use IDs that are stable in your own system (a SKU, a primary key) — not the display name, which can change.

## 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:

```json theme={null}
{ "amount": { "amountMinor": 450, "currency": "USD" } }
```

The price object also supports price types (`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](/developer-api/concepts/money).

## 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.                         |

Reference a shared group from an item or variation by `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](/developer-api/guides/menu-recipes) for worked examples.

<Note>
  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.
</Note>

## Tax and fees

These are top-level definitions you attach to items by ID:

* **Tax categories and rates** — rates can be `percentage`, `flat`, or `bracket`-based, on a configurable base, inclusive or exclusive. Attach with `taxCategoryId` / `taxRateIds`.
* **Fees** — surcharges and deposits (a bottle deposit or CRV), attached with `feeIds`.
* **Discounts, promotions, and coupons** — optional top-level collections for price reductions.

Most menus need a single tax rate and no fees; the richer constructs are there when a location needs them.

## 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.

Each window is a day plus a local time range:

* `dayOfWeek` — `0` (Sunday) through `6` (Saturday). Add one window per active day.
* `startTime` / `endTime` — local `HH:MM`, 24-hour.

Windows are evaluated in the **menu's timezone**, set by the top-level `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](/developer-api/guides/publish-menu#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](/developer-api/guides/menu-recipes#availability-daily-specials).

## Stock status

Stock status is `in_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 by `externalId`:

* Validation is all-or-nothing — a `400` lists 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.

So the simplest integration re-publishes the full menu whenever your source changes. See [Publish a menu](/developer-api/guides/publish-menu).
