Skip to content

Webhook Conversation Object (Legacy)

The legacy conversation block (id, origin.type, expiration_timestamp) in WhatsApp status webhooks, which the pricing object replaced under per-message pricing.

Also called: conversation object · conversation.origin.type · conversation_origin · Conversation block in status webhooks

Reviewed

Interactive lab

Hands on: use the controls to explore. Anything that plays on its own pauses while you are working inside it.

Scrub through the conversation object's lifetime

6 / 6

1 Oct 2026NowEvent 6 of 6

Service messages charged

Meta starts charging service messages. Billing for each reply is read from pricing.category and pricing.type — the conversation block has no role.

From the first conversation-based webhooks to today's per-message billing: step through each change to see what the conversation block reported and what took over from it.

Event 6 of 6: 1 Oct 2026 — Service messages charged (now). Meta starts charging service messages. Billing for each reply is read from pricing.category and pricing.type — the conversation block has no role.

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?

  1. Step 1

    Find every dependency

    Search code, SQL and BI models for conversation.id, origin.type, expiration_timestamp and columns such as conversation_origin or conversation_id. Each is a report or rule to migrate.

  2. Step 2

    Parse defensively

    Treat conversation as optional everywhere. A parser that reads status.conversation.origin.type without a null check breaks the day your app's webhooks move to a version that omits it.

  3. Step 3

    Move billing logic to the pricing object

    Use pricing.category for the rate and pricing.type for whether it was charged. Meta says pricing.billable will be deprecated, so do not build new logic on it.

  4. 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.

  5. 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?+
Only in limited cases. Meta's reference says it is omitted from webhooks on Graph API v24.0 and later, except for a free entry point conversation; older webhook versions may still include it, but it no longer describes what you are charged.
Why did my WhatsApp conversation count jump or drop to zero?+
Because the conversation object changed underneath the report. On v24.0+ webhooks it is omitted, so counts fall to zero; on v23.0 and older its id became unique per message, so distinct counts rise to message counts.
What replaced conversation.origin.type?+
The pricing object replaced it. pricing.category gives the category whose rate applies — note it spells authentication-international with a hyphen, where origin.type used an underscore — and pricing.type says whether the message was charged (regular) or free.
How do service replies appear in webhooks now?+
They appear in the pricing object with category service. Service messages have been charged since 1 October 2026, so read pricing.type to see whether a given reply was billed or fell inside a free entry point window; the conversation object plays no part.

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.

From definition to your first message

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.