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

# Menu recipes

> Worked menu fragments for the scenarios real restaurants need — multi-select modifiers, nested choices, dayparted specials, and happy-hour discounts.

These are copy-and-adapt fragments for common menu scenarios. Each shows only the relevant part of the menu document — drop it into the full structure from [Publish a menu](/developer-api/guides/publish-menu). For the model behind them, see [The menu model](/developer-api/concepts/the-menu-model).

All prices are integer minor units (`450` = \$4.50), and every object carries an `externalId` you own.

## Multi-select: choose up to 3, max 2 different

"Pick your toppings — up to 3 total, but no more than 2 different kinds." The total count and the distinct count are separate rules:

```json theme={null}
{
  "externalId": "grp-toppings",
  "name": "Toppings",
  "minSelections": 0,
  "maxSelections": 3,
  "maxUniqueSelections": 2,
  "options": [
    { "externalId": "top-mushroom", "name": "Mushroom", "maxQuantity": 3, "price": { "amount": { "amountMinor": 150, "currency": "USD" } } },
    { "externalId": "top-pepperoni", "name": "Pepperoni", "maxQuantity": 3, "price": { "amount": { "amountMinor": 200, "currency": "USD" } } },
    { "externalId": "top-olives", "name": "Olives", "maxQuantity": 3, "price": { "amount": { "amountMinor": 100, "currency": "USD" } } }
  ]
}
```

* `maxSelections: 3` caps the **total** quantity selected.
* `maxUniqueSelections: 2` caps the number of **distinct** options. A guest can take 2× Mushroom + 1× Olives (3 total, 2 kinds), but not three different toppings.
* `maxQuantity: 3` on each option allows doubling or tripling a single topping.

<Tip>
  Make the first selections free with `freeSelectionCount`. For example `"freeSelectionCount": 1` charges only from the
  second topping onward.
</Tip>

## Nested modifiers

A choice that opens further choices — pick a side, and if it's the salad, pick a dressing. Options can carry their own modifier groups:

```json theme={null}
{
  "externalId": "itm-combo",
  "name": "Burger Combo",
  "variations": [{ "externalId": "var-combo", "name": "Regular", "price": { "amount": { "amountMinor": 1200, "currency": "USD" } } }],
  "modifierGroups": [
    {
      "externalId": "grp-side",
      "name": "Choose your side",
      "minSelections": 1,
      "maxSelections": 1,
      "options": [
        { "externalId": "side-fries", "name": "Fries" },
        {
          "externalId": "side-salad",
          "name": "Side salad",
          "modifierGroups": [
            {
              "externalId": "grp-dressing",
              "name": "Dressing",
              "minSelections": 1,
              "maxSelections": 1,
              "options": [
                { "externalId": "drs-ranch", "name": "Ranch" },
                { "externalId": "drs-vinaigrette", "name": "Vinaigrette" }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

Choosing **Side salad** reveals a required **Dressing** choice; choosing **Fries** doesn't. Nest as deep as the menu needs.

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

## Availability: daily specials

A breakfast section that only shows on weekday mornings. Put the window on the category (it narrows everything inside) or on a single item:

```json theme={null}
{
  "externalId": "cat-breakfast",
  "name": "Breakfast",
  "availability": {
    "windows": [
      { "dayOfWeek": 1, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 2, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 3, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 4, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 5, "startTime": "07:00", "endTime": "11:00" }
    ]
  },
  "items": [{ "externalId": "itm-pancakes", "name": "Pancakes", "variations": [{ "externalId": "var-pancakes", "name": "Regular", "price": { "amount": { "amountMinor": 950, "currency": "USD" } } }] }]
}
```

* `dayOfWeek` is `0` (Sunday) through `6` (Saturday); add one window per active day.
* `startTime` / `endTime` are local `HH:MM` (24-hour), in the menu's timezone — set the top-level `timezone` (it [defaults to UTC](/developer-api/guides/publish-menu#set-the-timezone-for-availability)).
* An object with no `availability` is always available.

This is how time-of-day menus work — there's [one menu per location](/developer-api/concepts/the-menu-model#one-menu-per-location), and availability windows carve it up.

## Happy hour: a recurring discount

A recurring discount takes three top-level objects working together — what's targeted (a product set), the discount math, and when it's active (the promotion):

```json theme={null}
{
  "productSets": [
    { "externalId": "set-drinks", "name": "All drinks", "itemIdsAny": ["itm-latte", "itm-cold-brew"] }
  ],
  "discounts": [
    {
      "externalId": "disc-happy-hour",
      "name": "20% off drinks",
      "benefitType": "percentage",
      "percentage": 20,
      "benefitTargetProductSetId": "set-drinks"
    }
  ],
  "promotions": [
    {
      "externalId": "promo-happy-hour",
      "name": "Happy hour",
      "discountId": "disc-happy-hour",
      "applicationMode": "automatic",
      "availability": {
        "windows": [
          { "dayOfWeek": 1, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 2, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 3, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 4, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 5, "startTime": "16:00", "endTime": "18:00" }
        ]
      }
    }
  ]
}
```

* The **product set** says *what* the discount applies to (here, two drink items; use `"allProducts": true` for the whole menu).
* The **discount** says *how much* (20% off). Other `benefitType`s include `amount`, `set_price`, `free_item`, and `bxgy`.
* The **promotion** ties them together and says *when*: `applicationMode: "automatic"` applies it without a code, and `availability` gives the recurring weekly windows. Use `validFrom` / `validUntil` for a one-off campaign instead.

<Note>
  The IDs wiring these together — `discountId`, `benefitTargetProductSetId`, and the `itemIdsAny` members — are the
  `externalId`s you assigned. Cross-references in a menu always use your IDs, never Maple's. The promotion's
  `availability` windows use the menu's timezone (set the top-level `timezone`; it defaults to UTC).
</Note>

## 86 an item

Mark something out of stock without restructuring the menu — set `stockStatus` on the item (or variation):

```json theme={null}
{ "externalId": "itm-latte", "name": "Latte", "stockStatus": "out_of_stock", "variations": [{ "externalId": "var-latte", "name": "Regular", "price": { "amount": { "amountMinor": 450, "currency": "USD" } } }] }
```

`stockStatus` is `in_stock`, `out_of_stock`, or `low_stock`. Omitting it on a re-publish preserves the current value, so a stock update can be a small, targeted publish.

## Combine them

These compose. A breakfast category (availability) can hold a build-your-own item (nested modifiers) with a "first topping free" group (`freeSelectionCount`), all while a happy-hour promotion runs on drinks. Publish the whole menu and Maple applies it as one diff — see [Publish a menu](/developer-api/guides/publish-menu).
