Skip to main content
product.price_updated is a scoped event — unlike product.updated, it only carries prices. Every other product attribute (name, description, images, modifiers, etc.) is left untouched. Supports multiple products in a single event. When the change affects multiple stores, Fire emits a single event with all affected stores listed in targets. A modifier option’s price is contextual: it belongs to the combination (parent product × group × option), not to the option as a standalone product — the same option can be priced differently under two parents. That’s why it travels where it already lives in menu.updated: in products[].productModifiers[].overrides[], nested under the parent and scoped by the group’s modifierId. There is no separate array.

Payload

Fields

data

data.targets[n]

Same structure as in product.updated — includes vendorId and timezone.

data.targets[n].channels[n]

⚠️ listName in this event is the menu name (e.g. Menu App), while list.listName in menu.updated is an auto-generated label (IFOOD - Store 1350). They are not the same value and can’t be used to correlate — use listId, which is identical in both events.

data.products[n]

All four values come from the product’s item in the destination combination’s price list (the same one identified by listId), not from any default list. products[] includes the parent product of each option with a contextual price, even if its own price didn’t change: that way you always have the context of the product the change comes from. That priceInfo is the parent’s current price, so applying it is an idempotent replace (you write back the value it already has). If two edited options share the same parent, the parent appears only once. A product with no price in the destination list is omitted. ⚠️ An option’s base price does NOT travel in this event. This screen edits the contextual layer (the option’s price under a parent), never the option-product’s own price, so carrying the base price would assert a price that didn’t change — and since priceInfo is a full replace, it could overwrite the one you already have. The base price comes from the last menu.updated, where the option travels as a product of type MODIFIER, and it stays valid. If what changed is a product’s own price and that product also happens to be an option elsewhere, it arrives as a normal products[] entry: it’s a product edit, not an option edit. ⚠️ This priceInfo does not have the same fields as the priceInfo of products[n] in menu.updated / product.updated ({pointPrice, price, referencePrice, suggestedPrice}). They’re deliberately different: this event carries the sale price just saved along with its discount, not the product’s catalog prices.

data.products[n].productModifiers[n]

Same vocabulary as products[n].productModifiers[n] in menu.updated. Which groups arrive, and with what:
  • Only groups that have some contextual price under that parent. A missing group means “its options use their base price,” not “no change”: contextual prices are only added or updated, never removed, so absence always reflects the actual state.
  • Groups that do arrive bring all of their current contextual prices, not just the ones just edited. That lets you merge by modifierId without losing the ones you already had.
  • Unlike menu.updated, the group does not carry position: order is structure, and this event only carries prices. Keep the order you already have from the menu.
The key of a contextual price is the triple parent × modifierId × option’s productId. The nesting already expresses it: applying the price by looking up only the option’s productId is wrong, because the same option can appear under several parents, or under the same group assigned twice to the same parent (two different modifierIds), with different prices in each case. An override carries only price: an option’s contextual price has no discounted or suggested price of its own — those concepts only exist at the product level, in products[n].priceInfo.

Combos: arrive reconstructed

A COMBO has no price of its own: its value is derived from the options of its required groups. That’s why it’s emitted just like in menu.updatedprice: 0 and the actual value in referencePrice:
referencePrice = for every group with minOptions ≥ 1, minOptions × (lowest effective price among its options), summed across all those groups. Optional groups (minOptions = 0) don’t contribute.
minOptions doesn’t travel in this event — it’s a field of data.menu.modifierGroups[n] in menu.updated, correlated by modifierId. To recompute referencePrice you need both events: this one gives you the current contextual prices, menu.updated gives you which groups are required. Since changing a single option moves that value, when an option’s price changes on a combo the event carries, for all groups with a current contextual price under this parent — not just the edited group —, the full set of their overrides, so you can recompute the reference on your own and validate it against the one we send. As with any product, a required group with no current override does not appear in this event (see “Which groups arrive”); for its minimum use the base price of those options from menu.updated. Options with no resolvable price don’t participate in the minimum calculation.

Example

No group carries position. Cross-referencing modifierId with minOptions from menu.updated: ⚠️ If this combo also had a required group whose options all kept their base price (no override at all), that group wouldn’t appear in productModifiers[] — that doesn’t mean it was removed, just that there’s no contextual price to report. Its minimum comes from that modifierId’s options in menu.updated. ⚠️ A group having overrides doesn’t mean it’s required: 7c2f9d4e83a1b650 carries contextual prices for its options (they’re real add-ons, with their own price) but being optional (minOptions = 0) it doesn’t participate in the sum. On a regular product, options are add-ons and don’t change the parent’s price: the parent keeps its list price and carries no referencePrice.

Behavior

This event only changes prices. Name, description, images, modifiers, taxes, and every other attribute remain unchanged.
  • For products[n], the received priceInfo object fully replaces the existing one for that productId — it is not a field-by-field merge.
  • For productModifiers[n].overrides[n], price replaces that option’s contextual price only under this parent and this modifierId. Other occurrences of the same option are untouched.
  • An empty or absent array means “nothing to change here,” not “delete everything.”
  • A product appearing in products[] doesn’t mean its price changed: it may be there as the parent of an option (see data.products[n]). The replace is idempotent in that case.
A price change does not alter the product’s menu assignment date (additionalInfo.assignedAt): that value is membership data, not edit data. That’s why this event doesn’t carry it — the assignedAt you already have on record for that product stays valid. It arrives in product.updated and in menu.updated.

Usage

See Product publication for the full handling guide.