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

# Long Polling

> Fetch outbound events with GET /v2/updates

Long polling lets your integration fetch outbound events instead of receiving webhooks.

## Requirements

* API key delivery mode must be `polling`
* A bot can use either polling or webhooks, not both at the same time
* Requests use the same auth/signature flow as the rest of the API:
  * `Authorization: Bearer <API_KEY>`
  * `X-Timestamp: <Unix milliseconds>`
  * `X-Signature: HMAC-SHA256("{timestamp}.{uri}")` for this GET endpoint

## Endpoint

Use `GET /v2/updates`.

Query parameters:

| Parameter | Type    | Description                                                                  |
| --------- | ------- | ---------------------------------------------------------------------------- |
| `offset`  | string  | Opaque cursor from the previous response (`nextOffset`). Omit on first call. |
| `limit`   | integer | Max updates to return. Default `50`, max `100`.                              |
| `timeout` | integer | Wait time in seconds when no updates are available. Default `0`, max `30`.   |

Behavior:

* If updates exist after `offset`, response returns immediately
* If no updates and `timeout > 0`, request waits up to `timeout` seconds
* If still no updates, returns `updates: []` and a `nextOffset`

## Response Shape

```json theme={"theme":"github-dark"}
{
  "updates": [
    {
      "updateId": "AAAAAAABAAAAAAAAAAABAA==",
      "eventType": "message.created",
      "createdAt": 1699564800000,
      "data": {
        "message": {
          "id": "660e8400-e29b-41d4-a716-446655440001",
          "topicId": "550e8400-e29b-41d4-a716-446655440000",
          "senderId": "550e8400-e29b-41d4-a716-446655440001",
          "senderType": "user",
          "senderName": "Alice Johnson",
          "type": "text",
          "text": "Hello team!",
          "createdAt": 1699564800000
        },
        "truncated": false
      }
    }
  ],
  "nextOffset": "AAAAAAABAAAAAAAAAAABAA=="
}
```

Use `nextOffset` from each response as the `offset` in your next request.

## Event Payloads

Polling `data` payloads match webhook `data` payloads for the same event type.
See [Webhook Events](/api-reference/webhook-events) for field-level payload details.

## Mentions

Mentions are included in message events (`message.created`, `message.updated`).

* `data.message.mentions`: mention objects (`id`, `name`)
* `data.message.mentionedProfiles`: optional list of mentioned profile IDs

Example:

```json theme={"theme":"github-dark"}
{
  "eventType": "message.created",
  "data": {
    "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"
        }
      ]
    }
  }
}
```

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

## Attachments

Attachments are included directly in polling message events (`message.created`, `message.updated`)
under `data.message.attachments`.

Attachment fields:

| Field           | Type   | Description                                              |
| --------------- | ------ | -------------------------------------------------------- |
| `id`            | string | Attachment ID                                            |
| `type`          | string | `image`, `file`, `video`, `audio`                        |
| `name`          | string | Original filename (when available)                       |
| `url`           | string | Signed download URL                                      |
| `transcription` | object | Audio transcription status/details (voice messages only) |

Example:

```json theme={"theme":"github-dark"}
{
  "eventType": "message.created",
  "data": {
    "message": {
      "type": "audio",
      "attachments": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440088",
          "type": "audio",
          "name": "voice-note.mp3",
          "url": "https://storage.zenzap.co/attachments/...?token=...&expires=...",
          "transcription": {
            "status": "Pending"
          }
        }
      ]
    }
  }
}
```

Notes:

* Attachment `url` is signed and expires (currently 60 minutes)
* Voice transcription is asynchronous:
  * `message.created` usually arrives with `transcription.status: "Pending"`
  * `message.updated` can arrive later with `status: "Done"` and `text`

Supported event types:

* `message.created`
* `message.updated`
* `message.deleted`
* `reaction.added`
* `reaction.removed`
* `member.added`
* `member.removed`
* `topic.updated`

## Errors

* `400` bad request (invalid `offset`, `limit`, or `timeout`)
* `401` unauthorized
* `409` delivery mode is not polling, or provided `offset` is no longer available
* `500` internal server error
