Skip to content

Event types

Every event an endpoint can subscribe to. Each request body is an event, and data.object is the same resource the API returns.

message.*5

message.receivedObject: messageA customer sent a message to one of your numbers. data.object is the inbound message.
Payload
{
  "id": "evt_01j9x7q8r9s0t1v2w3x4y5z6a7",
  "object": "event",
  "type": "message.received",
  "version": "2",
  "created_at": "2026-10-01T09:29:12Z",
  "livemode": true,
  "workspace_id": "ws_12",
  "data": {
    "object": {
      "id": "imsg_88213",
      "object": "message",
      "livemode": true,
      "direction": "inbound",
      "channel": "whatsapp",
      "from": "+966501234567",
      "to": "+966112345678",
      "type": "text",
      "text": {
        "body": "مرحبا، أين طلبي؟"
      },
      "status": "received",
      "error": null,
      "reference": null,
      "conversation_id": null,
      "provider_message_id": "wamid.HBgMOTY2NTAxMjM0NTY3FQIAEhgUM0E",
      "contact": {
        "name": "Sara"
      },
      "context": null,
      "created_at": "2026-10-01T09:29:10Z",
      "updated_at": "2026-10-01T09:29:12Z"
    }
  }
}
message.sentObject: messageWhatsApp sent your message. data.previous_attributes.status is the status before.
message.deliveredObject: messageYour message reached the customer's phone.
Payload
{
  "id": "evt_01j9x7r2m3n4p5q6r7s8t9v0w1",
  "object": "event",
  "type": "message.delivered",
  "version": "2",
  "created_at": "2026-10-01T09:30:04Z",
  "livemode": true,
  "workspace_id": "ws_12",
  "data": {
    "object": {
      "id": "msg_48213",
      "object": "message",
      "livemode": true,
      "direction": "outbound",
      "channel": "whatsapp",
      "from": "+966112345678",
      "to": "+966501234567",
      "type": "text",
      "text": {
        "body": "أهلًا سارة! طلبك جاهز للاستلام 🎉"
      },
      "status": "delivered",
      "error": null,
      "reference": "order-10482",
      "conversation_id": "conv_311",
      "provider_message_id": "wamid.HBgMOTY2NTAxMjM0NTY3FQIAERgSMEM4",
      "created_at": "2026-10-01T09:30:00Z",
      "updated_at": "2026-10-01T09:30:04Z"
    },
    "previous_attributes": {
      "status": "sent"
    }
  }
}
message.readObject: messageThe customer opened your message. Only sent when the customer shares read receipts.
message.failedObject: messageYour message could not be delivered. data.object.error carries WhatsApp's code and reason (e.g. 131026 undeliverable, 131047 outside the 24-hour window).

contact.*5

contact.createdObject: contactA WhatsApp contact was added, from the portal, an import, a flow or the API. data.object is the contact with its tags and custom fields.
Payload
{
  "id": "evt_01j9x8a1b2c3d4e5f6g7h8j9k0",
  "object": "event",
  "type": "contact.created",
  "version": "2",
  "created_at": "2026-10-01T10:02:03Z",
  "livemode": true,
  "workspace_id": "ws_12",
  "data": {
    "object": {
      "id": "ct_1052",
      "object": "contact",
      "phone": "+966501234567",
      "email": "sara@example.com",
      "first_name": "سارة",
      "last_name": "القحطاني",
      "language": "ar",
      "country": "SA",
      "city": "الرياض",
      "gender": null,
      "birth_date": null,
      "notes": null,
      "opted_in": true,
      "consent": {
        "source": "website_form",
        "captured_at": "2026-10-01T10:02:00Z"
      },
      "opted_out_at": null,
      "bot_enabled": true,
      "tags": [
        {
          "id": "tag_12",
          "name": "عملاء VIP"
        }
      ],
      "fields": {
        "loyalty_points": "120"
      },
      "created_at": "2026-10-01T10:02:00Z",
      "updated_at": "2026-10-01T10:02:00Z"
    }
  }
}
contact.updatedObject: contactA contact's details, tags or custom fields changed. Several quick changes to one contact arrive as one event carrying the final state.
contact.deletedObject: contactA contact was deleted. data.object is {id, object: "contact", deleted: true}: the details are gone, so delete your copy too.
Payload
{
  "id": "evt_01j9x8b1c2d3e4f5g6h7j8k9m0",
  "object": "event",
  "type": "contact.deleted",
  "version": "2",
  "created_at": "2026-10-02T08:00:00Z",
  "livemode": true,
  "workspace_id": "ws_12",
  "data": {
    "object": {
      "id": "ct_1052",
      "object": "contact",
      "deleted": true
    }
  }
}
contact.opted_outObject: contactA contact asked to stop receiving business messages (they sent STOP, or someone opted them out). Queued campaign messages to them are cancelled; stop messaging them from your systems too.
contact.opted_inObject: contactA contact who had opted out agreed again to business messages (they sent START, or their consent was recorded). consent.source says how.

template.*1

template.status_changedObject: templateWhatsApp approved, rejected, paused or disabled one of your templates. data.object is the template; data.previous_attributes.status is where it was; rejection_reason says why when WhatsApp gave a reason.

campaign.*6

campaign.startedObject: campaignA campaign started sending, or was scheduled to. data.object is the campaign.
campaign.pausedObject: campaignA campaign was held, for example because Meta limited the sending number. hold_reason says why; resume it with POST /v1/campaigns/{id}/resume once the cause is fixed. data.object is the campaign.
campaign.resumedObject: campaignA held campaign is sending again. data.object is the campaign.
campaign.completedObject: campaignA campaign finished: every recipient was sent to or failed. stats has the final numbers. data.object is the campaign.
campaign.failedObject: campaignA campaign could not be sent, for example because Meta blocked delivery for a billing reason. data.object is the campaign.
campaign.cancelledObject: campaignA campaign was cancelled; its unsent messages will not go out. data.object is the campaign.

flow.*5

flow.run.startedObject: flow_runA flow started for a customer, from the API, a trigger or the inbox. data.object is the flow_run.
flow.run.handed_offObject: flow_runA flow handed the customer to your team; the conversation now needs a person. data.object is the flow_run.
flow.run.completedObject: flow_runA flow reached its end for a customer. variables holds everything it collected. data.object is the flow_run.
flow.run.expiredObject: flow_runA flow stopped waiting for a customer who did not answer in time. data.object is the flow_run.
flow.responseObject: flow_responseA customer submitted a WhatsApp Flow form. answers holds what they entered. data.object is the flow_response.

conversation.*5

conversation.createdObject: conversationA customer started a new conversation with the workspace. data.object is the conversation.
conversation.needs_agentObject: conversationA conversation is waiting for a person, because the bot handed it over or the customer asked for someone. Page your team, or assign it with POST /v1/conversations/{id}/assign.
Payload
{
  "id": "evt_01j9x9c1d2e3f4g5h6j7k8m9n0",
  "object": "event",
  "type": "conversation.needs_agent",
  "version": "2",
  "created_at": "2026-10-01T09:29:15Z",
  "livemode": true,
  "workspace_id": "ws_12",
  "data": {
    "object": {
      "id": "conv_311",
      "object": "conversation",
      "channel": "whatsapp",
      "customer": {
        "contact_id": "ct_1052",
        "address": "+966501234567",
        "name": "سارة القحطاني"
      },
      "number_id": "num_3",
      "state": "needs_agent",
      "open": true,
      "assignee": null,
      "unread": true,
      "label": null,
      "last_customer_message_at": "2026-10-01T09:29:10Z",
      "last_agent_message_at": null,
      "reply_window_expires_at": "2026-10-02T09:29:10Z",
      "resolved_at": null,
      "snoozed_until": null,
      "created_at": "2026-10-01T09:28:00Z",
      "updated_at": "2026-10-01T09:29:12Z"
    }
  }
}
conversation.assignedObject: conversationA conversation was assigned to a team member (assignee), by a person, a rule or the API.
conversation.resolvedObject: conversationA conversation was resolved. A good moment to send a satisfaction survey or close the ticket in your helpdesk.
conversation.reopenedObject: conversationA resolved conversation became active again, usually because the customer wrote.

webhook.*1

webhook.testObject: webhook_testSent when you press "Send test event" (or call the test endpoint). Carries no customer data.