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

# menu.updated v2

> Fired when a menu is created or updated and must be propagated to downstream systems.

A menu in Fire is a full catalog definition for a specific store and channel combination — including categories, products, modifier groups, and schedules. The payload is self-contained and ready to be forwarded to downstream systems. Treat it as an upsert: create the menu if it doesn't exist, replace it entirely if it does.

## Payload

```json theme={null}
{
  "event": {
    "id": "evt_def456",
    "type": "menu.updated",
    "executionId": "exec_abc123",
    "createdAt": "2025-01-15T14:31:00.000Z"
  },
  "data": {
    "account": "1",
    "country": "EC",
    "groupId": "a3f7c2d1-84be-4e10-9b3a-2c5d6e7f8091",
    "menu": {
      "list": {
        "listId": "805-iFood-delivery",
        "listName": "iFood - Store 805",
        "vendorId": "100.6.1350",
        "stores": [
          {
            "storeId": "b3d2a1f0-6e21-4c3a-9f5d-7a8b9c0d1e2f",
            "storeName": "Laboratorio Brasil",
            "timezone": "America/Sao_Paulo",
            "channels": [
              {
                "channelId": "0E049503-85CF-E511-80C6-000D3A3261F3",
                "channelReferenceName": "iFood",
                "schedules": [
                  { "day": "MONDAY",    "startTime": "07:00", "endTime": "23:00" },
                  { "day": "TUESDAY",   "startTime": "07:00", "endTime": "23:00" },
                  { "day": "WEDNESDAY", "startTime": "07:00", "endTime": "23:00" },
                  { "day": "THURSDAY",  "startTime": "07:00", "endTime": "23:00" },
                  { "day": "FRIDAY",    "startTime": "07:00", "endTime": "23:30" },
                  { "day": "SATURDAY",  "startTime": "08:00", "endTime": "23:30" },
                  { "day": "SUNDAY",    "startTime": "08:00", "endTime": "22:00" }
                ]
              }
            ]
          },
          {
            "storeId": "c4e3b2a1-7f32-4d4b-8a6e-8b9c0d1e2f3a",
            "storeName": "Vila Olimpia",
            "timezone": "America/Sao_Paulo",
            "channels": [
              {
                "channelId": "0E049503-85CF-E511-80C6-000D3A3261F3",
                "channelReferenceName": "iFood",
                "schedules": []
              }
            ]
          }
        ]
      },
      "categories": [
        {
          "productCategoryId": "cat_001",
          "name": "Burgers",
          "displayInList": true,
          "featured": false,
          "position": 1,
          "images": [
            {
              "imageCategoryId": "img_cat_001",
              "fileUrl": "https://cdn.example.com/categories/burgers.jpg"
            }
          ],
          "assignedAt": "2025-01-10T09:15:00Z",
          "productListing": [
            { "productId": "prod_001", "position": 1 }
          ],
          "schedules": [
            { "day": "MONDAY",    "startTime": "11:00", "endTime": "23:00" },
            { "day": "TUESDAY",   "startTime": "11:00", "endTime": "23:00" },
            { "day": "WEDNESDAY", "startTime": "11:00", "endTime": "23:00" },
            { "day": "THURSDAY",  "startTime": "11:00", "endTime": "23:00" },
            { "day": "FRIDAY",    "startTime": "11:00", "endTime": "23:30" },
            { "day": "SATURDAY",  "startTime": "11:00", "endTime": "23:30" },
            { "day": "SUNDAY",    "startTime": "11:00", "endTime": "22:00" }
          ]
        },
        {
          "productCategoryId": "cat_002",
          "name": "Breakfast",
          "displayInList": true,
          "featured": false,
          "position": 2,
          "images": [],
          "assignedAt": "2025-02-03T16:40:00Z",
          "productListing": [
            { "productId": "prod_002", "position": 1 }
          ],
          "schedules": null
        }
      ],
      "products": [
        {
          "productId": "prod_001",
          "name": "Classic Burger",
          "description": "Beef patty, lettuce, tomato, pickles",
          "active": true,
          "type": "PRODUCTO",
          "priceInfo": {
            "pointPrice": 0,
            "price": 1000,
            "referencePrice": 1200,
            "suggestedPrice": 1200
          },
          "productModifiers": [
            {
              "modifierId": "mod_001",
              "position": 1,
              "overrides": [
                {
                  "productId": "prod_size_small",
                  "priceInfo": { "price": 800 }
                }
              ]
            }
          ],
          "schedules": [
            { "day": "MONDAY",    "startTime": "11:00", "endTime": "23:00" },
            { "day": "TUESDAY",   "startTime": "11:00", "endTime": "23:00" },
            { "day": "WEDNESDAY", "startTime": "11:00", "endTime": "23:00" },
            { "day": "THURSDAY",  "startTime": "11:00", "endTime": "23:00" },
            { "day": "FRIDAY",    "startTime": "11:00", "endTime": "23:30" },
            { "day": "SATURDAY",  "startTime": "11:00", "endTime": "23:30" },
            { "day": "SUNDAY",    "startTime": "11:00", "endTime": "22:00" }
          ],
          "images": [
            {
              "imageCategoryId": "img_prod_001",
              "fileUrl": "https://cdn.example.com/products/classic-burger.jpg"
            }
          ],
          "taxInfo": [
            { "vatRatePercentage": 12 }
          ],
          "additionalInfo": {
            "externalCode": "11019#23211#231",
            "ncm": "21.00.21.32",
            "assignedAt": "2025-01-10T09:15:00Z"
          }
        },
        {
          "productId": "prod_002",
          "name": "Pancakes",
          "description": "Fluffy pancakes with maple syrup",
          "active": true,
          "type": "PRODUCTO",
          "priceInfo": {
            "pointPrice": 0,
            "price": 800,
            "referencePrice": 800,
            "suggestedPrice": 800
          },
          "productModifiers": [],
          "schedules": null,
          "images": [],
          "taxInfo": [
            { "vatRatePercentage": 12 }
          ],
          "additionalInfo": {
            "externalCode": "11019",
            "ncm": "19.05.90.90",
            "assignedAt": "2025-02-03T16:40:00Z"
          }
        },
        {
          "productId": "prod_size_small",
          "name": "Small",
          "description": "Small size",
          "active": true,
          "type": "MODIFIER",
          "priceInfo": {
            "pointPrice": 0,
            "price": 0,
            "referencePrice": 0,
            "suggestedPrice": 0
          },
          "productModifiers": [],
          "schedules": null,
          "images": [],
          "additionalInfo": {
            "externalCode": "11020",
            "ncm": "21.00.21.32"
          }
        },
        {
          "productId": "prod_size_large",
          "name": "Large",
          "description": "Large size",
          "active": true,
          "type": "MODIFIER",
          "priceInfo": {
            "pointPrice": 0,
            "price": 200,
            "referencePrice": 200,
            "suggestedPrice": 200
          },
          "productModifiers": [],
          "schedules": null,
          "images": [],
          "additionalInfo": {
            "externalCode": "11021",
            "ncm": "21.00.21.32"
          }
        }
      ],
      "modifierGroups": [
        {
          "modifierId": "mod_001",
          "modifier": "Choose your size",
          "minOptions": 1,
          "maxOptions": 1,
          "type": "RADIO",
          "modifierOptions": [
            { "optionId": "opt_001", "productId": "prod_size_small", "name": "Small", "position": 1 },
            { "optionId": "opt_002", "productId": "prod_size_large", "name": "Large", "position": 2 }
          ]
        }
      ]
    }
  }
}
```

## Fields

### `data`

| Field     | Type   | Description                                                                                                                                    |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `account` | string | Account identifier                                                                                                                             |
| `country` | string | ISO 3166-1 alpha-2 country code (e.g. `EC`, `BR`, `CO`) — required by downstream systems                                                       |
| `groupId` | string | UUID that correlates events from the same publication or sync batch. Multiple `menu.updated` events emitted together share the same `groupId`. |
| `menu`    | object | Complete menu definition                                                                                                                       |

### `data.menu`

| Field            | Type      | Description                                 |
| ---------------- | --------- | ------------------------------------------- |
| `list`           | object    | Menu metadata and channel/store association |
| `categories`     | object\[] | Menu categories                             |
| `products`       | object\[] | Product catalog                             |
| `modifierGroups` | object\[] | Modifier groups and options                 |

### `data.menu.list`

| Field      | Type             | Description                                                                                                                                                                                                                                                                        |
| ---------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listId`   | string           | Composite identifier: `{storeNumber}-{channelCode}-{fulfillmentType}`                                                                                                                                                                                                              |
| `listName` | string           | Auto-generated label `{channelCode} - Store {storeNumber}` (e.g. `"iFood - Store 805"`). **Not** the menu's own name nor the store's operational name. The menu's name travels in `channels[n].listName` of [`product.price_updated`](/en/webhook-reference/product-price-updated) |
| `vendorId` | string \| number | Brand code                                                                                                                                                                                                                                                                         |
| `stores`   | object\[]        | Stores this menu applies to                                                                                                                                                                                                                                                        |

### `data.menu.list.stores[n]`

| Field       | Type           | Description                                                                                                                                                                                                                                                                                                                                                       |
| ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `storeId`   | string         | Internal store UUID (PK `stores.id`) — **not** the `store_number`. Same convention as `targets[n].storeId` in [`product.price_updated`](/en/webhook-reference/product-price-updated) and [`product.availability_changed`](/en/webhook-reference/product-availability-changed). The `store_number` only appears inside `list.listId` and as a `storeName` fallback |
| `storeName` | string         | Store operational name. Fallback: `"Store #{store_number}"`                                                                                                                                                                                                                                                                                                       |
| `timezone`  | string \| null | Store IANA timezone (e.g. `America/Sao_Paulo`). `null` if not configured                                                                                                                                                                                                                                                                                          |
| `channels`  | object\[]      | Sales channels this store is published to                                                                                                                                                                                                                                                                                                                         |

### `data.menu.list.stores[n].channels[n]`

| Field                  | Type      | Description                                                                                                                                                                                                                                                      |
| ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channelId`            | string    | Internal sales channel UUID (PK `channels.id`) — **not** the aggregator's external `channel_id`. Same convention as `targets[n].channels[n].channelId` in the product events                                                                                     |
| `channelReferenceName` | string    | **Fulfillment** reference name (e.g. `delivery`, `pickup`) — not the sales channel. ⚠️ Does not pair with `channelId`, which is the sales channel: in the product events (`targets[n].channels[n]`) `channelReferenceName` is the **channel** (`iFood`, `Rappi`) |
| `schedules`            | object\[] | Time windows when this channel is active for this store. An empty array (`[]`) means the channel operates 24 hours.                                                                                                                                              |

### `data.menu.list.stores[n].channels[n].schedules[n]`

| Field       | Type   | Description                                                                                   |
| ----------- | ------ | --------------------------------------------------------------------------------------------- |
| `day`       | string | Day of the week: `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY` |
| `startTime` | string | Opening time in `HH:mm` format                                                                |
| `endTime`   | string | Closing time in `HH:mm` format                                                                |

### `data.menu.categories[n]`

| Field               | Type              | Description                                                                                           |
| ------------------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
| `productCategoryId` | string            | Category identifier                                                                                   |
| `name`              | string            | Display name                                                                                          |
| `displayInList`     | boolean           | Whether the category is visible                                                                       |
| `featured`          | boolean           | Whether the category is featured                                                                      |
| `position`          | number            | Display order                                                                                         |
| `images`            | object\[]         | Category images — `{ imageCategoryId, fileUrl }`                                                      |
| `assignedAt`        | string \| null    | Date the category joined the menu, in ISO 8601 UTC. See [Menu assignment date](#menu-assignment-date) |
| `productListing`    | object\[]         | Products in this category with their positions — `{ productId, position }`                            |
| `schedules`         | object\[] \| null | Category-specific schedule. Always present; `null` if no schedule is configured                       |

### `data.menu.products[n]`

| Field                         | Type              | Description                                                                                                                                                           |
| ----------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`                   | string \| number  | Product identifier (`externalId` or UUID)                                                                                                                             |
| `name`                        | string            | Product name                                                                                                                                                          |
| `description`                 | string            | Product description                                                                                                                                                   |
| `active`                      | boolean           | Menu visibility (`visible`); does not reflect stock or operational availability                                                                                       |
| `type`                        | string            | Item type: `PRODUCTO`, `MODIFIER`, `COMPLEMENT`, `COMBO`                                                                                                              |
| `priceInfo`                   | object            | Resolved product prices                                                                                                                                               |
| `priceInfo.pointPrice`        | number            | Points price                                                                                                                                                          |
| `priceInfo.price`             | number            | Resolved price (`resolved_price` / `final_price`; `0` for combos)                                                                                                     |
| `priceInfo.referencePrice`    | number            | Reference price when applicable in the catalog                                                                                                                        |
| `priceInfo.suggestedPrice`    | number            | Suggested price when applicable in the catalog                                                                                                                        |
| `productModifiers`            | object\[]         | Modifier group references — `{ modifierId, position, overrides? }`                                                                                                    |
| `schedules`                   | object\[] \| null | Product custom schedule. Always present on every `products[]` item (incl. modifier option stubs); `null` if using store hours or no custom schedule                   |
| `images`                      | object\[]         | Product images                                                                                                                                                        |
| `taxInfo`                     | object\[]         | Tax information — `{ vatRatePercentage }`                                                                                                                             |
| `upselling`                   | string            | Suggested upselling product (optional)                                                                                                                                |
| `additionalInfo`              | object            | Optional extra metadata for the product                                                                                                                               |
| `additionalInfo.externalCode` | string            | External code identifying the product in a third-party system. May be a single code (e.g. `11019`) or a composite key with `#` as separator (e.g. `11019#23211#231`). |
| `additionalInfo.ncm`          | string            | NCM (Nomenclatura Comum do Mercosul) fiscal classification code (e.g. `21.00.21.32`).                                                                                 |
| `additionalInfo.assignedAt`   | string \| null    | Date the product joined the menu, in ISO 8601 UTC. Absent on items that only exist as a modifier group option. See [Menu assignment date](#menu-assignment-date)      |

### `data.menu.products[n].productModifiers[n].overrides[n]`

| Field             | Type   | Description                                                                                                                                                                                                                            |
| ----------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`       | string | Modifier option this override applies to                                                                                                                                                                                               |
| `priceInfo`       | object | Price override for this specific option on this product and menu                                                                                                                                                                       |
| `priceInfo.price` | number | **Only field.** The override is a one-off, contextual price: the option's other prices (reference, suggested, points) have no value of their own within a specific product — they're read from the option as a product in `products[]` |

### `data.menu.modifierGroups[n]`

| Field             | Type      | Description                                                                     |
| ----------------- | --------- | ------------------------------------------------------------------------------- |
| `modifierId`      | string    | Modifier group identifier                                                       |
| `modifier`        | string    | Display name of the modifier group                                              |
| `minOptions`      | number    | Minimum number of selections required                                           |
| `maxOptions`      | number    | Maximum number of selections allowed                                            |
| `type`            | string    | Selection type: `RADIO` (single) or `CHECKBOX` (multiple)                       |
| `modifierOptions` | object\[] | Individual options within the group — each `productId` must exist in `products` |

### `data.menu.modifierGroups[n].modifierOptions[n]`

| Field       | Type   | Description                 |
| ----------- | ------ | --------------------------- |
| `optionId`  | string | Option identifier           |
| `productId` | string | Product used as this option |
| `name`      | string | Option name                 |
| `position`  | number | Display order               |

## Menu assignment date

`categories[n].assignedAt` and `products[n].additionalInfo.assignedAt` indicate **when the entity joined the menu**. This is **membership** data, not edit data: it doesn't change when you edit the price, name, description, image, modifiers, order, or visibility.

**Format:** ISO 8601 with **second** precision and a `Z` suffix — `"2026-08-04T12:30:00Z"`. Always in **UTC**, never in the store's zone: the value is the same fact for every store in the menu, which can be in different countries. To display it in local time, use the `timezone` carried per store in `list.stores[n]`. No milliseconds — unlike `event.createdAt`, which does carry them.

| Situation                                                                 | Value                                                                                                                           |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Product or category added to the menu                                     | Date it was added                                                                                                               |
| Any later edit (price, name, image, order, `active`)                      | Unchanged                                                                                                                       |
| Product removed from the menu and re-added                                | **New** date — the field describes **current** membership, not the first one in its history                                     |
| Product present in multiple categories of the same menu                   | The **oldest** of its additions (`products[n]` carries a single value, even if the product appears in several `productListing`) |
| Product or category inherited from a parent menu                          | The **parent's** date, not the child menu's                                                                                     |
| Item that only exists as an option of a modifier group (`type: MODIFIER`) | Absent — it isn't a menu member on its own                                                                                      |
| Category left with no products and later given some again                 | New date — the category is recreated                                                                                            |
| Menu published before the field existed                                   | Absent until the first re-publish of that store/channel                                                                         |

There is no `assignedAt` at the `list` or `list.stores[n]` level: the field describes when the entity joined the **menu**, not when a store started receiving it.

The same field, with the same semantics, travels in [`product.updated`](/en/webhook-reference/product-updated). It does **not** travel in [`product.price_updated`](/en/webhook-reference/product-price-updated) or [`product.availability_changed`](/en/webhook-reference/product-availability-changed): those events only carry their delta, and the `assignedAt` you already have on record stays valid.

## Notes

* The payload is a **complete menu** — not a diff. Replace the entire menu on the downstream system.
* Every `menu.modifierGroups[n].modifierOptions[n].productId` must reference a product defined in `menu.products`.
* **`stores[n].channels[n].schedules`:** time windows when the channel is active for that store. An empty array (`[]`) means the channel operates 24 hours — no restrictions.
* **`categories[].schedules`:** category-specific schedule if it exists; `null` if none.
* **`products[].schedules`:** only when the product has schedule `mode: custom`; `null` if using store hours or no custom schedule.

## Removing a menu externally

Fire does not emit a separate delete event for menus. To remove a menu from a downstream system, Fire sends a `menu.updated` event with `menu.categories`, `menu.products`, and `menu.modifierGroups` as empty arrays. Your system should treat an empty menu as a signal to deactivate or remove the menu externally.

This clearing removes categories and products from the menu. If the menu is published again, they get re-added: they arrive with a **new** `assignedAt`, not their original date — same rule as "product removed from the menu and re-added".

```json theme={null}
{
  "event": {
    "id": "evt_def459",
    "type": "menu.updated",
    "executionId": "exec_abc124",
    "createdAt": "2025-01-15T14:31:00.000Z"
  },
  "data": {
    "account": "1",
    "country": "EC",
    "groupId": "a3f7c2d1-84be-4e10-9b3a-2c5d6e7f8091",
    "menu": {
      "list": { "..." : "..." },
      "categories": [],
      "products": [],
      "modifierGroups": []
    }
  }
}
```

## Usage

See [Menu publication](/en/guides/menu-publication) for the full handling guide.
