Documentation / Complete
Catalog shopping carts
Building with AI? Connect it to your account over MCP: it checks your setup, creates webhooks and templates with your confirmation and writes the code for you. See how →
When a customer builds a cart from the business's WhatsApp catalog and sends it, you get a message.received with data.message.type: "order" and Meta's order object as is, not flattened: catalog_id (the catalog), text (the comment they wrote with the cart; it is "" when they wrote nothing: the field is there, empty) and product_items[], one per product, with product_retailer_id (the product's id in the catalog), quantity, item_price (unit price) and currency.
A product without a price arrives with item_price: 0 and currency: "USD", even if the rest of the catalog is in pesos or another currency. You cannot tell it apart from a free product: treat 0 as "to be quoted" and ignore currency in that case.
With Coexistence, carts arrive the same way. The catalog is managed in the WhatsApp Business app: Meta does not allow managing it by API for this kind of business (its error says "SMB business type").
# Nothing to call: this is what WAIA Connect POSTs to your webhook for a cart.
# {
# "id": "evt_7f3a1b2c9d4e5f6a7b8c9d0e1f2a3b4c",
# "type": "message.received",
# "version": "1",
# "createdAt": "2026-10-13T01:43:06.000Z",
# "connection": { "id": "conn_4eede070e5a84d1590bdce2ea1d837bc", "phoneNumber": "+5493510000000", "externalId": "almacen-sur" },
# "sequence": 12346,
# "data": {
# "message": {
# "from": "5493511234567",
# "id": "wamid.HBgL…",
# "timestamp": "1791855786",
# "type": "order",
# "order": {
# "catalog_id": "100200300400500",
# "text": "¿Me lo mandan el sábado?",
# "product_items": [
# { "product_retailer_id": "yerba-1kg", "quantity": 2, "item_price": 4500, "currency": "ARS" },
# { "product_retailer_id": "mate-calabaza", "quantity": 1, "item_price": 0, "currency": "USD" }
# ]
# }
# },
# "contacts": [ { "wa_id": "5493511234567", "profile": { "name": "Ana" } } ]
# }
# }
# List the items of a saved body (item_price 0 = no price in the catalog → to be quoted):
jq -r '.data.message.order.product_items[]
| "\(.product_retailer_id) x\(.quantity) " + (if .item_price == 0 then "to be quoted" else "\(.item_price) \(.currency)" end)' body.jsonSending products or the catalog through /v1 is not available today: POST /v1/messages accepts text, templates and media.
A product the business sends from the phone app reaches you as message.echo (origin: "device") with type: "interactive" and interactive.type: "product". The rest of interactive is built by Meta: read it without assuming any field.
A message Meta does not deliver through the API arrives as message.received with type: "unsupported" and Meta's errors[] (for example 131051) saying why. It has no content to read.
Deduplicate as with any message: on the envelope id (evt_…) or on data.message.id.