messaging_handovers Webhook

Field reference for WhatsApp messaging_handovers webhooks: Conversation Routing thread ownership changes, control_passed and control_taken payloads, role fields, deduplication, and why Dualhook does not subscribe to it.

The messaging_handovers field tells an app when ownership of a WhatsApp conversation thread changes under Meta's Conversation Routing. When several responders share one business phone number (for example your app, another partner's app, and Meta Business Agent), exactly one owns each thread. Each notification names the role that held the thread before and the role that holds it now.

What messaging_handovers Reports

There are two notification types, named in value.type:

TypeDelivered toMeaning
control_passedThe new ownerThe current owner passed the thread to you through the Thread control API. You are now expected to reply.
control_takenThe previous ownerThe designated escalation partner took the thread. Stop replying to the user.

Role identifiers used in the owner fields are customer_service, marketing, utility, ctwa, ai_agent, and escalation.

When It Fires

  • control_passed fires when the thread owner calls pass on the Thread control API.
  • control_taken fires when the designated escalation partner takes the thread, either explicitly through the Thread control API or implicitly by sending a Service message.

A release names no new owner, so it produces no notification. The next responder is chosen by entry-point routing when the user sends their next message. A thread also returns to idle on its own after 24 hours of user inactivity, without a notification.

Payload Shape

Every notification uses the same envelope:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<WABA_ID>",
      "changes": [
        {
          "field": "messaging_handovers",
          "value": {
            "messaging_product": "whatsapp",
            "sender": { "phone_number": "<WHATSAPP_USER_PHONE_NUMBER>" },
            "recipient": {
              "phone_number_id": "<PHONE_NUMBER_ID>",
              "display_phone_number": "<BUSINESS_PHONE_NUMBER>"
            },
            "type": "control_passed",
            "timestamp": "<UNIX_SECONDS>",
            "control_passed": {
              "previous_owner_role": "ai_agent",
              "new_owner_role": "escalation",
              "metadata": "WhatsApp user requested human agent",
              "conversation_context": {
                "type": "summary",
                "summary": { "text": "AI-generated summary string" }
              }
            }
          }
        }
      ]
    }
  ]
}

object, entry[].id, field, messaging_product, recipient.phone_number_id, recipient.display_phone_number, type, and timestamp are always present. sender.phone_number and everything inside the control_passed or control_taken object are optional.

control_passed

FieldNotes
previous_owner_roleRole of the responder that passed control.
new_owner_roleRole of the responder that received control.
new_owner_app_idIncluded only when the new owner is identified by app rather than by business.
metadataThe free-form string from the pass request, up to 2,000 characters.
conversation_contextOptional AI-generated summary. Not sent if you already receive standby events for the conversation.
previous_owner_app_id, previous_owner_app_roleDeprecated and slated for removal. previous_owner_app_role only ever holds meta_business_agent. Use the role fields instead.

control_taken

FieldNotes
previous_owner_roleRole of the responder that lost control.
new_owner_roleAlways escalation, because only the designated escalation partner can take a thread.
new_owner_app_idIncluded only when the escalation partner is identified by app.
metadataFor an explicit take, the caller's string (up to 2,000 characters). For an implicit take, Control taken via service message.
previous_owner_app_idDeprecated. Absent when a partner loses the thread. control_taken has no previous_owner_app_role.

Dualhook Handling

Dualhook subscription: not subscribed. Dualhook's Meta app does not subscribe to messaging_handovers, so a Dualhook connection never delivers it to you, even though Meta allows Webhook Override for this field. Dualhook has no Thread control or Conversation Routing features, and the Runtime API has no thread control route.

To use Conversation Routing, configure routing in Meta Business Suite and subscribe your own Meta app to messaging_handovers before routing applies to the number.

Enabling Meta Business Agent creates or changes a routing configuration even if you never set one up. The agent becomes the primary responder for new conversations and previous primary responders move to standby, so on a Dualhook connection those conversations stop reaching your endpoint. See AI agents on WhatsApp Business.

Implementation Notes

  • Key ownership state on previous_owner_role and new_owner_role, not on the deprecated app ID fields.
  • Update ownership from these notifications. Meta has no endpoint that reports the current thread owner.
  • Deduplicate on recipient.phone_number_id, type, timestamp, and the user. Those first three alone are not unique, because timestamp is in whole seconds and two users can hand over in the same second.
  • Identify the user from sender.phone_number when present, otherwise from the identifier you already track for the thread. A phone number and a BSUID for the same user are one person.
  • If you cannot identify the user, apply the update idempotently instead of dropping it.

Related

  • Webhook Subscription FieldsReference list of all 22+ WhatsApp Business Platform webhook subscription fields, what each notifies you of, required permissions, payload size limits, retry policy, and IP allowlisting.
  • standby WebhookField reference for WhatsApp standby webhooks: passive Conversation Routing view of threads another responder owns, inbound messages, message echoes, status receipts, prerequisites, and why Dualhook does not subscribe to it.
  • WhatsApp Webhook OverrideHow Dualhook uses WhatsApp Webhook Override to route supported customer-path webhooks directly from Meta to your server.
  • Meta BSUID, Usernames & Contact Book Transition GuideOverview of Meta's WhatsApp BSUID rollout: usernames, contact book behavior, parent BSUIDs, API recipient support, webhook changes, and migration timeline.
Browse more docsStart Free Trial