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

> Disparado quando um menu é criado ou atualizado e deve ser propagado para sistemas externos.

Um menu no Fire é a definição completa do catálogo para uma combinação específica de loja e canal — incluindo categorias, produtos, grupos de modificadores e horários. O payload é autocontido e pronto para ser encaminhado a sistemas externos. Trate-o como um upsert: crie o menu se não existir ou substitua-o inteiramente se já existir.

## 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": "Hambúrgueres",
          "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": "Café da Manhã",
          "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": "X-Burguer Clássico",
          "description": "Hambúrguer bovino, alface, tomate, picles",
          "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": "Panquecas",
          "description": "Panquecas fofas com calda de bordo",
          "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": "Pequeno",
          "description": "Tamanho pequeno",
          "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": "Grande",
          "description": "Tamanho grande",
          "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": "Escolha o tamanho",
          "minOptions": 1,
          "maxOptions": 1,
          "type": "RADIO",
          "modifierOptions": [
            { "optionId": "opt_001", "productId": "prod_size_small", "name": "Pequeno", "position": 1 },
            { "optionId": "opt_002", "productId": "prod_size_large", "name": "Grande", "position": 2 }
          ]
        }
      ]
    }
  }
}
```

## Campos

### `data`

| Campo     | Tipo   | Descrição                                                                                                                                                  |
| --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `account` | string | Identificador da conta                                                                                                                                     |
| `country` | string | Código do país ISO 3166-1 alpha-2 (ex.: `EC`, `BR`, `CO`) — necessário para sistemas externos                                                              |
| `groupId` | string | UUID que correlaciona eventos do mesmo batch de publicação ou sincronização. Vários eventos `menu.updated` emitidos juntos compartilham o mesmo `groupId`. |
| `menu`    | object | Definição completa do menu                                                                                                                                 |

### `data.menu`

| Campo            | Tipo      | Descrição                                 |
| ---------------- | --------- | ----------------------------------------- |
| `list`           | object    | Metadados do menu e associação canal/loja |
| `categories`     | object\[] | Categorias do menu                        |
| `products`       | object\[] | Catálogo de produtos                      |
| `modifierGroups` | object\[] | Grupos de modificadores e opções          |

### `data.menu.list`

| Campo      | Tipo             | Descrição                                                                                                                                                                                                                                                               |
| ---------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listId`   | string           | Identificador composto: `{storeNumber}-{channelCode}-{fulfillmentType}`                                                                                                                                                                                                 |
| `listName` | string           | Rótulo autogerado `{channelCode} - Store {storeNumber}` (ex.: `"iFood - Store 805"`). **Não** é o nome do menu nem o nome operacional da loja. O nome do menu viaja em `channels[n].listName` de [`product.price_updated`](/pt/webhook-reference/product-price-updated) |
| `vendorId` | string \| number | Código da marca                                                                                                                                                                                                                                                         |
| `stores`   | object\[]        | Lojas às quais este menu se aplica                                                                                                                                                                                                                                      |

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

| Campo       | Tipo           | Descrição                                                                                                                                                                                                                                                                                                                                                         |
| ----------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `storeId`   | string         | UUID interno da loja (PK `stores.id`) — **não** é o `store_number`. Mesma convenção que `targets[n].storeId` de [`product.price_updated`](/pt/webhook-reference/product-price-updated) e [`product.availability_changed`](/pt/webhook-reference/product-availability-changed). O `store_number` só aparece dentro de `list.listId` e como fallback de `storeName` |
| `storeName` | string         | Nome operacional da loja. Fallback: `"Store #{store_number}"`                                                                                                                                                                                                                                                                                                     |
| `timezone`  | string \| null | Fuso horário IANA da loja (ex.: `America/Sao_Paulo`). `null` se não configurado                                                                                                                                                                                                                                                                                   |
| `channels`  | object\[]      | Canais de vendas nos quais esta loja é publicada                                                                                                                                                                                                                                                                                                                  |

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

| Campo                  | Tipo      | Descrição                                                                                                                                                                                                                                                         |
| ---------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channelId`            | string    | UUID interno do canal de vendas (PK `channels.id`) — **não** é o `channel_id` externo do agregador. Mesma convenção que `targets[n].channels[n].channelId` dos eventos de produto                                                                                 |
| `channelReferenceName` | string    | Nome de referência do **fulfillment** (ex.: `delivery`, `pickup`) — não do canal de vendas. ⚠️ Não forma par com `channelId`, que é do canal de vendas: nos eventos de produto (`targets[n].channels[n]`) `channelReferenceName` é o **canal** (`iFood`, `Rappi`) |
| `schedules`            | object\[] | Janelas de tempo em que este canal está ativo para esta loja. Um array vazio (`[]`) indica que o canal opera 24 horas.                                                                                                                                            |

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

| Campo       | Tipo   | Descrição                                                                                   |
| ----------- | ------ | ------------------------------------------------------------------------------------------- |
| `day`       | string | Dia da semana: `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, `SUNDAY` |
| `startTime` | string | Horário de abertura no formato `HH:mm`                                                      |
| `endTime`   | string | Horário de fechamento no formato `HH:mm`                                                    |

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

| Campo               | Tipo              | Descrição                                                                                                              |
| ------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `productCategoryId` | string            | Identificador da categoria                                                                                             |
| `name`              | string            | Nome de exibição                                                                                                       |
| `displayInList`     | boolean           | Se a categoria está visível                                                                                            |
| `featured`          | boolean           | Se a categoria está em destaque                                                                                        |
| `position`          | number            | Ordem de exibição                                                                                                      |
| `images`            | object\[]         | Imagens da categoria — `{ imageCategoryId, fileUrl }`                                                                  |
| `assignedAt`        | string \| null    | Data em que a categoria entrou no menu, em ISO 8601 UTC. Ver [Data de atribuição ao menu](#data-de-atribuição-ao-menu) |
| `productListing`    | object\[]         | Produtos desta categoria com suas posições — `{ productId, position }`                                                 |
| `schedules`         | object\[] \| null | Horário próprio da categoria. Sempre presente; `null` se não houver horário configurado                                |

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

| Campo                         | Tipo              | Descrição                                                                                                                                                                                      |
| ----------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`                   | string \| number  | Identificador do produto (`externalId` ou UUID)                                                                                                                                                |
| `name`                        | string            | Nome do produto                                                                                                                                                                                |
| `description`                 | string            | Descrição do produto                                                                                                                                                                           |
| `active`                      | boolean           | Visibilidade no menu (`visible`); não reflete estoque nem disponibilidade operacional                                                                                                          |
| `type`                        | string            | Tipo de item: `PRODUCTO`, `MODIFIER`, `COMPLEMENT`, `COMBO`                                                                                                                                    |
| `priceInfo`                   | object            | Preços resolvidos do produto                                                                                                                                                                   |
| `priceInfo.pointPrice`        | number            | Preço em pontos                                                                                                                                                                                |
| `priceInfo.price`             | number            | Preço resolvido (`resolved_price` / `final_price`; `0` para combos)                                                                                                                            |
| `priceInfo.referencePrice`    | number            | Preço de referência quando aplicável no catálogo                                                                                                                                               |
| `priceInfo.suggestedPrice`    | number            | Preço sugerido quando aplicável no catálogo                                                                                                                                                    |
| `productModifiers`            | object\[]         | Referências de grupos de modificadores — `{ modifierId, position, overrides? }`                                                                                                                |
| `schedules`                   | object\[] \| null | Horário customizado do produto. Sempre presente em todos os itens de `products[]` (incl. stubs de opções modifier); `null` se usa horário da loja ou não tem horário customizado               |
| `images`                      | object\[]         | Imagens do produto                                                                                                                                                                             |
| `taxInfo`                     | object\[]         | Informação fiscal — `{ vatRatePercentage }`                                                                                                                                                    |
| `upselling`                   | string            | Produto sugerido para upselling (opcional)                                                                                                                                                     |
| `additionalInfo`              | object            | Metadados extras opcionais do produto                                                                                                                                                          |
| `additionalInfo.externalCode` | string            | Código externo que identifica o produto em um sistema de terceiros. Pode ser um código simples (ex.: `11019`) ou uma chave composta com `#` como separador (ex.: `11019#23211#231`).           |
| `additionalInfo.ncm`          | string            | Código de classificação fiscal NCM (Nomenclatura Comum do Mercosul, ex.: `21.00.21.32`).                                                                                                       |
| `additionalInfo.assignedAt`   | string \| null    | Data em que o produto entrou no menu, em ISO 8601 UTC. Ausente nos itens que só existem como opção de um grupo de modificadores. Ver [Data de atribuição ao menu](#data-de-atribuição-ao-menu) |

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

| Campo             | Tipo   | Descrição                                                                                                                                                                                                                     |
| ----------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `productId`       | string | Opção do modificador à qual este override se aplica                                                                                                                                                                           |
| `priceInfo`       | object | Override de preço para esta opção específica neste produto e menu                                                                                                                                                             |
| `priceInfo.price` | number | **Único campo.** O override é um preço pontual e contextual: os demais preços da opção (referência, sugerido, pontos) não têm valor próprio dentro de um produto específico — são lidos da opção como produto em `products[]` |

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

| Campo             | Tipo      | Descrição                                                                 |
| ----------------- | --------- | ------------------------------------------------------------------------- |
| `modifierId`      | string    | Identificador do grupo de modificadores                                   |
| `modifier`        | string    | Nome de exibição do grupo                                                 |
| `minOptions`      | number    | Número mínimo de seleções obrigatórias                                    |
| `maxOptions`      | number    | Número máximo de seleções permitidas                                      |
| `type`            | string    | Tipo de seleção: `RADIO` (single) ou `CHECKBOX` (multiple)                |
| `modifierOptions` | object\[] | Opções individuais do grupo — cada `productId` deve existir em `products` |

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

| Campo       | Tipo   | Descrição                     |
| ----------- | ------ | ----------------------------- |
| `optionId`  | string | Identificador da opção        |
| `productId` | string | Produto usado como esta opção |
| `name`      | string | Nome da opção                 |
| `position`  | number | Ordem de exibição             |

## Data de atribuição ao menu

`categories[n].assignedAt` e `products[n].additionalInfo.assignedAt` indicam **quando a entidade entrou no menu**. É um dado de **pertencimento**, não de edição: não muda ao editar o preço, o nome, a descrição, a imagem, os modificadores, a ordem nem a visibilidade.

**Formato:** ISO 8601 com precisão de **segundos** e sufixo `Z` — `"2026-08-04T12:30:00Z"`. Sempre em **UTC**, nunca no fuso da loja: o valor é o mesmo fato para todas as lojas do menu, que podem estar em países diferentes. Para exibir em horário local, use o `timezone` que viaja por loja em `list.stores[n]`. Sem milissegundos — diferente de `event.createdAt`, que os leva.

| Situação                                                                      | Valor                                                                                                                             |
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Produto ou categoria adicionado ao menu                                       | Data da inclusão                                                                                                                  |
| Qualquer edição posterior (preço, nome, imagem, ordem, `active`)              | Sem alteração                                                                                                                     |
| Produto removido do menu e adicionado novamente                               | Data **nova** — o campo descreve o pertencimento **vigente**, não o primeiro da história                                          |
| Produto presente em várias categorias do mesmo menu                           | A **mais antiga** de suas inclusões (em `products[n]` vai um único valor, mesmo que o produto apareça em vários `productListing`) |
| Produto ou categoria herdado de um menu pai                                   | A data do **pai**, não a do menu filho                                                                                            |
| Item que só existe como opção de um grupo de modificadores (`type: MODIFIER`) | Ausente — não é membro do menu por si só                                                                                          |
| Categoria que ficou sem produtos e depois volta a ter                         | Data nova — a categoria é recriada                                                                                                |
| Menu publicado antes de o campo existir                                       | Ausente até a primeira republicação daquela loja/canal                                                                            |

Não existe `assignedAt` no nível `list` nem `list.stores[n]`: o campo descreve quando a entidade entrou no **menu**, não quando uma loja passou a recebê-lo.

O mesmo campo, com a mesma semântica, viaja em [`product.updated`](/pt/webhook-reference/product-updated). **Não** viaja em [`product.price_updated`](/pt/webhook-reference/product-price-updated) nem em [`product.availability_changed`](/pt/webhook-reference/product-availability-changed): esses eventos transmitem apenas seu delta, e o `assignedAt` que você já tem registrado continua válido.

## Notas

* O payload é um **menu completo** — não um diff. Substitua o menu inteiro no sistema externo.
* Cada `menu.modifierGroups[n].modifierOptions[n].productId` deve referenciar um produto definido em `menu.products`.
* **`stores[n].channels[n].schedules`:** janelas de tempo em que o canal está ativo para aquela loja. Um array vazio (`[]`) indica que o canal opera 24 horas — sem restrições.
* **`categories[].schedules`:** horário próprio da categoria se existir; `null` se não houver.
* **`products[].schedules`:** apenas quando o produto tem schedule `mode: custom`; `null` se usa horário da loja ou não tem horário customizado.

## Remover um menu externamente

O Fire não emite um evento de exclusão separado para menus. Para remover um menu de um sistema externo, o Fire envia um evento `menu.updated` com `menu.categories`, `menu.products` e `menu.modifierGroups` como arrays vazios. Seu sistema deve interpretar um menu vazio como sinal para desativar ou remover o menu externamente.

Esse esvaziamento remove categorias e produtos do menu. Se o menu for publicado de novo, eles são reincorporados: chegam com `assignedAt` **novo**, não com a data original — mesma regra de "produto removido do menu e adicionado novamente".

```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": []
    }
  }
}
```

## Uso

Consulte o guia [Publicação de menu](/pt/guides/menu-publication) para o fluxo completo de processamento.
