> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenzap.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook Events

> Reference for webhook event payloads delivered to your endpoint

When you configure a webhook, Zenzap sends HTTP POST requests to your URL when events occur. This page documents the payload structure for each event type.

## Event Envelope

All webhook events share the same envelope structure:

```json theme={"theme":"github-dark"}
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.created",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": { ... }
}
```

| Field          | Type    | Description                             |
| -------------- | ------- | --------------------------------------- |
| `id`           | string  | Unique event ID (use for deduplication) |
| `type`         | string  | Event type (see below)                  |
| `eventVersion` | integer | Schema version (currently `1`)          |
| `timestamp`    | integer | Unix timestamp in milliseconds          |
| `data`         | object  | Event-specific payload                  |

## HTTP Headers

Each webhook delivery includes these headers:

| Header                 | Description                             |
| ---------------------- | --------------------------------------- |
| `X-Zenzap-Event`       | Event type (e.g., `message.created`)    |
| `X-Zenzap-Signature`   | HMAC-SHA256 signature for verification  |
| `X-Zenzap-Timestamp`   | Unix timestamp (milliseconds) when sent |
| `X-Zenzap-Delivery-Id` | Unique delivery ID (for deduplication)  |

### Signature Verification

When a secret is configured, verify webhooks by calculating:

```python theme={"theme":"github-dark"}
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        f"{timestamp}.{payload.decode()}".encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
```

***

## Message Events

### message.created

Sent when a new message is posted in a topic where your bot is a member.

```json theme={"theme":"github-dark"}
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.created",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "message": {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "topicId": "550e8400-e29b-41d4-a716-446655440000",
      "senderId": "550e8400-e29b-41d4-a716-446655440001",
      "senderName": "Alice Johnson",
      "senderType": "user",
      "type": "text",
      "text": "Hello team!",
      "createdAt": 1699564800000
    }
  }
}
```

### message.updated

Sent when a message is edited or when voice message transcription completes.

```json theme={"theme":"github-dark"}
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.updated",
  "eventVersion": 1,
  "timestamp": 1699564850000,
  "data": {
    "message": {
      "id": "660e8400-e29b-41d4-a716-446655440001",
      "topicId": "550e8400-e29b-41d4-a716-446655440000",
      "senderId": "550e8400-e29b-41d4-a716-446655440001",
      "senderName": "Alice Johnson",
      "senderType": "user",
      "type": "text",
      "text": "Hello team! (edited)",
      "createdAt": 1699564800000,
      "updatedAt": 1699564850000
    }
  }
}
```

### message.deleted

Sent when a message is deleted.

```json theme={"theme":"github-dark"}
{
  "id": "evt_550e8400-e29b-41d4-a716-446655440099",
  "type": "message.deleted",
  "eventVersion": 1,
  "timestamp": 1699564900000,
  "data": {
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "deletedBy": "550e8400-e29b-41d4-a716-446655440001"
  }
}
```

***

## Message Object

The `message` object in message events contains:

| Field               | Type    | Description                                                 |
| ------------------- | ------- | ----------------------------------------------------------- |
| `id`                | string  | Message UUID                                                |
| `topicId`           | string  | Topic UUID                                                  |
| `senderId`          | string  | Sender ID (format: `{uuid}` for users, `b@{uuid}` for bots) |
| `senderName`        | string  | Sender's display name                                       |
| `senderType`        | string  | `user`, `bot`, or `system`                                  |
| `type`              | string  | Message type (see below)                                    |
| `text`              | string  | Message text (may be empty for non-text types)              |
| `createdAt`         | integer | Creation timestamp (ms)                                     |
| `updatedAt`         | integer | Last update timestamp (ms)                                  |
| `parentId`          | string  | Replied-to message ID                                       |
| `mentionedProfiles` | array   | Mentioned profile IDs (in mention order)                    |
| `attachments`       | array   | File attachments                                            |
| `mentions`          | array   | User mentions                                               |
| `location`          | object  | Location data (for location messages)                       |
| `task`              | object  | Task data (for task messages)                               |
| `contact`           | object  | Contact data (for contact messages)                         |

### Message Types

| Type       | Description          | Additional Fields                      |
| ---------- | -------------------- | -------------------------------------- |
| `text`     | Regular text message | `text`                                 |
| `image`    | Image attachment     | `attachments[]`                        |
| `file`     | File attachment      | `attachments[]`                        |
| `video`    | Video attachment     | `attachments[]`                        |
| `audio`    | Voice message        | `attachments[]` (with `transcription`) |
| `location` | Shared location      | `location`                             |
| `task`     | Task snapshot        | `task`                                 |
| `contact`  | Shared contact       | `contact`                              |

***

## Attachments

File attachments include a signed download URL:

```json theme={"theme":"github-dark"}
{
  "attachments": [
    {
      "id": "att_550e8400-e29b-41d4-a716-446655440088",
      "type": "image",
      "name": "screenshot.png",
      "url": "https://storage.zenzap.co/attachments/...?token=...&expires=..."
    }
  ]
}
```

<Warning>
  **Attachment URLs expire after 60 minutes.** Download files promptly after receiving the webhook.
</Warning>

### Voice Message Transcription

Voice messages (audio attachments) are automatically transcribed. The flow is:

1. **`message.created`** arrives with `transcription.status: "Pending"`
2. **`message.updated`** arrives when transcription completes

```json theme={"theme":"github-dark"}
{
  "type": "message.updated",
  "data": {
    "message": {
      "type": "audio",
      "attachments": [
        {
          "id": "att_...",
          "type": "audio",
          "name": "voice-note.mp3",
          "url": "https://storage.zenzap.co/...",
          "transcription": {
            "status": "Done",
            "text": "Hey team, just a quick update on the project..."
          }
        }
      ]
    }
  }
}
```

**Transcription Status Values:**

| Status    | Description                       |
| --------- | --------------------------------- |
| `Pending` | Queued for transcription          |
| `Started` | Transcription in progress         |
| `Done`    | Complete - `text` field populated |
| `Failed`  | Transcription failed              |

***

## Mentions

To create mentions via External API message sending, use `<@profileId>` in message text.

Example request text:

```text theme={"theme":"github-dark"}
Hi <@550e8400-e29b-41d4-a716-446655440001>, can you review this?
```

In webhook payloads, mentions are returned under `message.mentions`.
`message.mentionedProfiles` may also be present as a compact ID list.

```json theme={"theme":"github-dark"}
{
  "message": {
    "text": "Hi <@550e8400-e29b-41d4-a716-446655440001>, can you review this?",
    "mentionedProfiles": ["550e8400-e29b-41d4-a716-446655440001"],
    "mentions": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "Alice Johnson"
      }
    ]
  }
}
```

`message.text` keeps the mention token format (`<@profileId>`), while `mentions[]` provides resolved display names.

`mentions` fields:

| Field  | Type   | Description          |
| ------ | ------ | -------------------- |
| `id`   | string | Mentioned profile ID |
| `name` | string | Mention display name |

***

## Reply Messages

Messages that reply to other messages include:

```json theme={"theme":"github-dark"}
{
  "message": {
    "id": "msg_new",
    "text": "I agree!",
    "parentId": "msg_original"
  }
}
```

***

## Location Messages

```json theme={"theme":"github-dark"}
{
  "message": {
    "type": "location",
    "text": "",
    "location": {
      "latitude": "37.7749",
      "longitude": "-122.4194",
      "name": "San Francisco Office",
      "address": "123 Market St, San Francisco, CA"
    }
  }
}
```

`address` is optional and is included only when available.

***

## Task Messages

Task snapshots are sent when tasks are created, updated, or their status changes:

```json theme={"theme":"github-dark"}
{
  "message": {
    "type": "task",
    "text": "",
    "task": {
      "id": "task_...",
      "action": "Added",
      "title": "Review documentation",
      "text": "Please review the API docs by Friday",
      "status": "Open",
      "assignee": "550e8400-e29b-41d4-a716-446655440001",
      "dueDate": 1699651200000,
      "isDueDateTimeSelected": true,
      "parentId": null,
      "subItemsCount": 0
    }
  }
}
```

**Task Actions:**

| Action           | Description           |
| ---------------- | --------------------- |
| `Added`          | Task created          |
| `Updated`        | Task details changed  |
| `Deleted`        | Task removed          |
| `MarkedAsDone`   | Task completed        |
| `MarkedAsOpened` | Task reopened         |
| `Replied`        | Comment added to task |

***

## Contact Messages

```json theme={"theme":"github-dark"}
{
  "message": {
    "type": "contact",
    "text": "",
    "contact": {
      "name": "John Doe",
      "phoneNumbers": ["+1234567890"],
      "emails": ["john@example.com"],
      "role": "Engineer",
      "location": "San Francisco",
      "linkedIn": "https://linkedin.com/in/johndoe",
      "profileId": "550e8400-e29b-41d4-a716-446655440001"
    }
  }
}
```

***

## Reaction Events

### reaction.added

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "reaction.added",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "emoji": "👍",
    "userId": "550e8400-e29b-41d4-a716-446655440001",
    "userName": "Alice Johnson"
  }
}
```

### reaction.removed

Same structure as `reaction.added`.

***

## Member Events

### member.added

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "member.added",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "memberId": "550e8400-e29b-41d4-a716-446655440003",
    "memberName": "Carol Williams",
    "addedBy": "550e8400-e29b-41d4-a716-446655440001"
  }
}
```

### member.removed

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "member.removed",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "memberId": "550e8400-e29b-41d4-a716-446655440003",
    "memberName": "Carol Williams",
    "removedBy": "550e8400-e29b-41d4-a716-446655440001"
  }
}
```

***

## Topic Events

### topic.updated

Sent when a topic's name or description is changed.

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "topic.updated",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Project Updates - Q4",
    "updatedBy": "550e8400-e29b-41d4-a716-446655440001"
  }
}
```

Only changed fields are included in the payload. If only the description was updated, `name` would be absent.

***

## Poll Vote Events

### poll\_vote.created

Sent when a user votes on a poll in a topic where your bot is a member.

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "poll_vote.created",
  "eventVersion": 1,
  "timestamp": 1699564800000,
  "data": {
    "pollVoteId": "att_550e8400_opt1_550e8400-e29b-41d4-a716-446655440001",
    "attachmentId": "att_550e8400-e29b-41d4-a716-446655440088",
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "optionId": "opt1",
    "voterId": "550e8400-e29b-41d4-a716-446655440001",
    "createdAt": 1699564800000
  }
}
```

### poll\_vote.deleted

Sent when a user removes their vote from a poll.

```json theme={"theme":"github-dark"}
{
  "id": "evt_...",
  "type": "poll_vote.deleted",
  "eventVersion": 1,
  "timestamp": 1699564900000,
  "data": {
    "pollVoteId": "att_550e8400_opt1_550e8400-e29b-41d4-a716-446655440001",
    "attachmentId": "att_550e8400-e29b-41d4-a716-446655440088",
    "messageId": "660e8400-e29b-41d4-a716-446655440001",
    "topicId": "550e8400-e29b-41d4-a716-446655440000",
    "optionId": "opt1",
    "voterId": "550e8400-e29b-41d4-a716-446655440001"
  }
}
```

***

## Retry & Auto-Pause Behavior

* Webhooks are retried up to 3 times with exponential backoff on failure
* After 10 consecutive failures, the webhook is automatically paused
* Re-enable a paused webhook via the [Update webhook configuration](/api-reference/webhooks/update-webhook-configuration) endpoint
