product.price_updated é um evento restrito — diferente de product.updated, transmite apenas preços. Os demais atributos do produto (nome, descrição, imagens, modificadores etc.) permanecem sem alteração.
Suporta múltiplos produtos em um único evento. Quando a alteração afeta várias lojas, o Fire emite um único evento com todas as lojas afetadas listadas em targets.
O preço de uma opção de modificador é contextual: pertence à combinação (produto pai × grupo × opção), não à opção como produto avulso — a mesma opção pode valer diferente sob dois pais. Por isso ele viaja onde já vive em menu.updated: em products[].productModifiers[].overrides[], aninhado sob o pai e delimitado pelo modifierId do grupo. Não existe um array separado.
Payload
Campos
data
data.targets[n]
Mesma estrutura que em product.updated — inclui vendorId e timezone.
data.targets[n].channels[n]
⚠️
listName neste evento é o nome do menu (ex.: Menu App), enquanto
list.listName em menu.updated é um rótulo autogerado (IFOOD - Store 1350). Não são o
mesmo valor e não servem para correlacionar — use listId, que é idêntico em ambos os eventos.
data.products[n]
Os quatro valores vêm do item do produto na lista de preços da combinação destino
(a mesma identificada por
listId), não de nenhuma lista padrão.
products[] inclui o produto pai de cada opção com preço contextual, mesmo que o preço dele
não tenha mudado: assim você sempre tem o contexto do produto de onde vem a alteração. Esse
priceInfo é o preço vigente do pai, então aplicá-lo é um replace idempotente (você escreve o
valor que ele já tem). Se duas opções editadas compartilham o mesmo pai, o pai aparece uma única
vez. Um produto sem preço na lista destino é omitido.
⚠️ O preço base de uma opção NÃO viaja neste evento. Esta tela edita a camada
contextual (o preço da opção sob um pai), nunca o preço próprio do produto-opção, então
transmitir o base afirmaria um preço que não mudou — e como priceInfo é replace total, poderia
sobrescrever o que você já tem. O base você tem do último
menu.updated, onde a opção viaja como produto do tipo
MODIFIER, e continua válido.
Se o que foi editado é o preço próprio de um produto que também é opção em outro lugar, esse produto
chega como entrada normal de products[]: é uma edição de produto, não de opção.
⚠️ Este priceInfo não tem os mesmos campos que o priceInfo de products[n] em
menu.updated / product.updated
({pointPrice, price, referencePrice, suggestedPrice}). São deliberadamente diferentes: este evento
transmite o preço de venda recém-salvo com seu desconto, não os preços de catálogo do produto.
data.products[n].productModifiers[n]
Mesmo vocabulário que products[n].productModifiers[n] de
menu.updated.
Quais grupos chegam e com quê:
- Somente os grupos que têm algum preço contextual sob esse pai. Um grupo ausente significa “suas opções usam o preço base”, não “sem alteração”: os preços contextuais só são adicionados ou atualizados, nunca removidos, então a ausência sempre reflete o estado real.
- Dos grupos que chegam, vem a totalidade de seus preços contextuais vigentes, não só os
recém-editados. Assim você pode fazer merge por
modifierIdsem perder os que já tinha. - Diferente de
menu.updated, o grupo não trazposition: a ordem é estrutura e este evento só transmite preços. Mantenha a ordem que você já tem do menu.
modifierId × productId da opção. O
aninhamento já a expressa: aplicar o preço buscando apenas pelo productId da opção é
incorreto, porque a mesma opção pode aparecer sob vários pais, ou sob o mesmo grupo atribuído
duas vezes ao mesmo pai (dois modifierId distintos), com preços diferentes em cada caso.
Um override traz apenas price: um preço contextual de opção não tem preço com desconto nem
sugerido próprios — esses conceitos existem apenas no nível do produto, em products[n].priceInfo.
Combos: chegam reconstruídos
Um COMBO não tem preço próprio: seu valor é derivado das opções de seus grupos obrigatórios. Por isso ele é emitido igual amenu.updated — price: 0
e o valor real em referencePrice:
referencePrice= para cada grupo comminOptions ≥ 1,minOptions × (menor preço efetivo entre suas opções), somado entre todos esses grupos. Grupos opcionais (minOptions = 0) não contribuem.
minOptions não viaja neste evento — é um campo de
data.menu.modifierGroups[n] em
menu.updated, correlacionado por modifierId. Para recalcular referencePrice você precisa dos
dois eventos: este te dá os preços contextuais vigentes, menu.updated te dá quais grupos são
obrigatórios.
Como alterar uma única opção move esse valor, quando o preço de uma opção de um combo é
editado, o evento traz, de todos os grupos com preço contextual vigente sob este pai — não só
o grupo editado —, a totalidade de seus overrides, para que você possa recalcular a referência
por conta própria e validá-la contra a que enviamos. Assim como em qualquer produto, um grupo
obrigatório sem nenhum override vigente não aparece neste evento (ver
“Quais grupos chegam e com quê”); para seu mínimo use o preço
base dessas opções em menu.updated. Opções sem preço resolúvel não participam do cálculo do
mínimo.
Exemplo
position. Cruzando modifierId com minOptions de menu.updated:
⚠️ Se este combo tivesse também um grupo obrigatório cujas opções mantivessem todas o preço base
(sem nenhum override), esse grupo não apareceria em
productModifiers[] — não significa que
foi removido, apenas que não há preço contextual a informar. Seu mínimo vem das opções desse
modifierId em menu.updated.
⚠️ Um grupo ter overrides não implica que seja obrigatório: 7c2f9d4e83a1b650 traz preços
contextuais para suas opções (são add-ons reais, com preço próprio) mas, por ser opcional
(minOptions = 0), não participa da soma.
Em um produto normal, as opções são add-ons e não alteram o preço do pai: o pai mantém seu
price de lista e não traz referencePrice.
Comportamento
Este evento só altera preços. Nome, descrição, imagens, modificadores, impostos e demais atributos permanecem sem alteração.- Para
products[n], o objetopriceInforecebido substitui totalmente o existente para aqueleproductId— não é um merge campo a campo. - Para
productModifiers[n].overrides[n],pricesubstitui o preço contextual dessa opção somente sob este pai e estemodifierId. As demais ocorrências da mesma opção não são tocadas. - Um array vazio ou ausente significa “nada a mudar aqui”, não “apagar tudo”.
- Um produto aparecer em
products[]não implica que seu preço mudou: ele pode estar ali como pai de uma opção (verdata.products[n]). O replace é idempotente nesse caso.
additionalInfo.assignedAt): esse valor é de pertencimento, não de edição. Por isso este evento
não o transmite — o assignedAt que você já tem registrado para esse produto continua válido. Ele
chega em product.updated e
em menu.updated.

