01What is the webhook conversation object?
The webhook conversation object is a legacy block of the statuses webhook. Under conversation-based pricing, which ran from 1 February 2022 to 30 June 2025, status webhooks for outbound messages carried a conversation object. It held an id for the 24-hour billable conversation the message belonged to, an origin object whose type named the conversation category, and — on the sent status — an expiration_timestamp marking when the conversation would end. Reports were built on it: counting distinct conversation.id values grouped by origin.type was how most teams estimated their WhatsApp bill.
The values of origin.type followed the pricing model. In the first version they were business_initiated, user_initiated and referral_conversion. From June 2023 they became categories — marketing, utility, authentication and service — with referral_conversion still marking a free entry point conversation, and Meta's reference later lists authentication_international and marketing_lite as well.
On 1 July 2025 Meta switched to per-message pricing, charging each delivered message, and the conversation stopped being the billing unit. The pricing object now carries the billing signal: pricing_model is PMP, category names the rate applied, and type says whether the message was charged (regular) or not (free_customer_service, free_entry_point). Meta's reference states that the conversation object is omitted entirely from webhooks on Graph API v24.0 and later, unless the webhook is for a free entry point conversation — where its id identifies that free window. On v23.0 and older webhooks the object can still appear, but its id is now set to a unique value per message.
So the conversation object is a legacy field, and the webhook pricing object is its replacement. Where the old block described a thread that could hold many messages for one fee, the pricing object describes how each individual message is billed — which is the only view that reconciles with today's invoices.
Key takeaways
- The conversation object (id, origin.type, expiration_timestamp) named the 24-hour billable conversation a sent message belonged to.
- It was the billing unit until 30 June 2025; since 1 July 2025 Meta charges per delivered message.
- Webhooks on Graph API v24.0 and later omit it, except for messages in a free entry point conversation.
- On v23.0 and older webhooks its id is now unique per message, so counting distinct IDs counts messages, not conversations.
- Use the pricing object — pricing.category and pricing.type — for any billing or reporting logic today.
02Why does the webhook conversation object matter?
Dashboards and billing reconciliation jobs written before July 2025 still group by conversation_origin or count conversation.id. On webhook versions that omit the object they quietly report zero; on older versions, where each id is now unique per message, they suddenly count messages; and in neither case do they match the bill, because one conversation can contain many charged messages. Migrating those reports to the pricing object is the difference between a finance team that trusts the WhatsApp numbers and one that rebuilds them from invoices every month.
03 · How it works, step by step
How does the webhook conversation object work?
- Step 1
Find every dependency
Search code, SQL and BI models for
conversation.id,origin.type,expiration_timestampand columns such asconversation_originorconversation_id. Each is a report or rule to migrate. - Step 2
Parse defensively
Treat
conversationas optional everywhere. A parser that readsstatus.conversation.origin.typewithout a null check breaks the day your app's webhooks move to a version that omits it. - Step 3
Move billing logic to the pricing object
Use
pricing.categoryfor the rate andpricing.typefor whether it was charged. Meta sayspricing.billablewill be deprecated, so do not build new logic on it. - Step 4
Count delivered messages, not conversations
Store one pricing record per wamid and count it only once the message is delivered or read — Meta bills delivered messages, and a read implies delivery.
- Step 5
Keep history labelled
Rows from before 1 July 2025 carry
pricing_model: "CBP"and belong to the conversation era. Keep them in their own report rather than mixing them with per-message rows.
04The webhook conversation object in code
{"id": "wamid.HBgMOTE5ODEyMzQ1Njc4FQIAERgSMEE3QjQ5RkI2","status": "sent","timestamp": "1717231200","recipient_id": "919812345678","conversation": {"id": "6ba2c5d1e8a04c9f8f7b3e21a9d4c0aa","expiration_timestamp": "1717317600","origin": { "type": "utility" }},"pricing": {"billable": true,"pricing_model": "CBP","category": "utility"}}
June 2024: the conversation id, its category and when the 24-hour conversation would expire.
05 · Common mistakes, and the fix
Common mistakes with the webhook conversation object
Estimating the bill from conversations
Per-message pricing charges every delivered message by category. Counting conversations undercounts charges whenever a thread holds more than one billed message.
Crashing on a missing object
Code that dereferences conversation.origin.type fails as soon as the block is absent. Make it optional before upgrading the webhook version.
Reading a free entry point marker as a charge
The object still appears for free entry point conversations. Use it as a window marker if you like, but take billing from pricing.type, which reads free_entry_point there.
Counting distinct conversation IDs on older versions
On v23.0 and older webhooks the conversation id is now unique per message, so a distinct count that once meant conversations now means messages that carried the block. Retire the metric rather than reinterpret it.
Mixing CBP and PMP rows
A year-on-year chart that adds conversation counts to message counts compares different units. Split by pricing_model and label the eras.
06The webhook conversation object: key facts and limits
- Fields
- id · origin.type · expiration_timestamp (sent only)
- Billing unit until
- 30 June 2025
- Origin types listed now
- marketing, marketing_lite, utility, authentication, authentication_international, service, referral_conversion
- On v24.0+ webhooks
- Omitted, except for free entry point conversations
- Replacement
- pricing.category + pricing.type
- pricing_model
- CBP (before 1 July 2025) · PMP (since)
07Example: A Mumbai broker's vanishing conversations
A Mumbai insurance broker's monthly dashboard showed "utility conversations" falling to almost zero after its app's webhooks moved to a newer Graph API version, while the WhatsApp invoice stayed the same. The dashboard counted distinct conversation.id values, and the object had stopped arriving. The team rebuilt the tile as delivered messages by pricing.category and pricing.type, labelled everything before July 2025 as conversation-era history, and the dashboard and invoice agreed again.
08Webhook Conversation Object (Legacy) FAQs
Is the conversation object still sent in WhatsApp webhooks?+
Why did my WhatsApp conversation count jump or drop to zero?+
What replaced conversation.origin.type?+
How do service replies appear in webhooks now?+
09 · Tips from the bench
Best practices for the webhook conversation object
- Add a contract test with a status payload that has no conversation block.
- Keep the raw webhook JSON so old reports can be recomputed if a definition changes.
- Reconcile per-message counts against Meta's pricing analytics each month before trusting a new dashboard.