> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.zorvia.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.zorvia.io/_mcp/server.

# Webhook events

> Event types and JSON payloads sent by Zorvia channel webhooks.

Your webhook endpoint receives a JSON payload whenever a supported message event occurs on the channel. Use `event.type` to choose how your application handles the delivery.

## Event types

| Event              | When it is sent                                        |
| ------------------ | ------------------------------------------------------ |
| `message.received` | New message activity is available for the channel.     |
| `message.edited`   | The content of an existing message changes.            |
| `message.deleted`  | A message is deleted from Zorvia.                      |
| `message.removed`  | A message is revoked or removed from the conversation. |
| `message.failed`   | Zorvia cannot deliver a message.                       |

> **Note**
>
> Use the `message` object, including its sender and lifecycle timestamps, to determine the direction and current state of a `message.received` event.

## Example payload

```json
{
  "event": {
    "type": "message.received",
    "source": null,
    "occurred_at": "2026-07-23T10:14:52+00:00"
  },
  "workspace": {
    "id": "workspace_01JQ8XNZ2JQZ7J4HQYN7A5H6F3"
  },
  "channel": {
    "id": "8aa25bf5-f24d-4f9f-b4ab-287d41a29aa3",
    "name": "Customer Support",
    "driver": "whatsapp"
  },
  "connection": {
    "id": "01JQ8Z21R8VZ0N59S7E7R4GPH1",
    "driver": "webhook-server",
    "name": "Order status integration"
  },
  "conversation": {
    "id": "01JQ8YVVTBVAJ7QEW49GB0N2H5",
    "type": "direct",
    "name": "Ada Okafor"
  },
  "message": {
    "id": "01JQ8Z5E2V4PTHB63SF7F4CJA2",
    "conversation_id": "01JQ8YVVTBVAJ7QEW49GB0N2H5",
    "sender_id": "01JQ8YT9G39ZC9V91G7J71C49T",
    "sender_type": "contact",
    "content": "Hello, I need help with my order.",
    "type": "text",
    "is_template": false,
    "driver": "whatsapp",
    "is_reply": false,
    "is_comment": false,
    "parent_id": null,
    "meta": {},
    "created_at": "2026-07-23T10:14:52+00:00",
    "updated_at": "2026-07-23T10:14:52+00:00",
    "deleted_at": null,
    "sent_at": null,
    "delivered_at": null,
    "edited_at": null,
    "removed_at": null,
    "received_at": "2026-07-23T10:14:52+00:00",
    "failed_at": null,
    "lifecycle_timestamp": "2026-07-23T10:14:52+00:00"
  }
}
```

Fields such as `sender`, `media`, `quoted_message`, and `forwarded_message` are included when they apply to the message.

## Payload fields

| Field               | Type             | Description                                                                                 |
| ------------------- | ---------------- | ------------------------------------------------------------------------------------------- |
| `event.type`        | `string`         | The event name used to route the delivery in your application.                              |
| `event.occurred_at` | `string`         | When the event occurred, formatted as an ISO 8601 timestamp.                                |
| `event.source`      | `object \| null` | Information about the originating connection, when available.                               |
| `workspace.id`      | `string`         | The Zorvia workspace that owns the channel.                                                 |
| `channel`           | `object`         | The channel where the message activity occurred.                                            |
| `connection`        | `object`         | The webhook configuration that sent the delivery.                                           |
| `conversation`      | `object`         | The affected conversation. Its values can be `null` when no conversation is available.      |
| `message`           | `object`         | The affected message, including its content, type, relationships, and lifecycle timestamps. |

### Message lifecycle fields

The `message` object contains timestamps that help your application update its local state:

| Field          | Description                              |
| -------------- | ---------------------------------------- |
| `created_at`   | When the message record was created.     |
| `sent_at`      | When the message was sent successfully.  |
| `received_at`  | When Zorvia received the message.        |
| `delivered_at` | When delivery was confirmed.             |
| `edited_at`    | When the message was last edited.        |
| `removed_at`   | When the message was removed or revoked. |
| `failed_at`    | When message delivery failed.            |

Timestamps are ISO 8601 strings or `null` when that lifecycle stage has not occurred.

## Handling events

Webhook deliveries can arrive more than once or out of order. Store `message.id`, compare `event.occurred_at` with the state you have already processed, and make each handler idempotent.

Use the signing instructions in [Set up a webhook](/webhooks/setup) to verify that deliveries came from Zorvia.