# Get an event

> One event, as a webhook received it.

`GET /v1/events/{id}`

One event, as a webhook received it.

Needs a key with the `messages:read` scope. [Keys and scopes](https://usebluebot.com/docs/concepts/api-keys)

## Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | The event’s id. Starts with `evt_` |

## Example

```bash
curl "https://usebluebot.com/api/v1/events/evt_1Hq2LxW9cVbN3mKpRtYs0a" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"
```

```ts
import BlueBot from '@usebluebot/sdk';

const client = new BlueBot({ apiKey: process.env.BLUEBOT_API_KEY });

const event = await client.events.get('evt_1Hq2LxW9cVbN3mKpRtYs0a');
console.log(event);
```

```python
import os
from bluebot import BlueBot

client = BlueBot(api_key=os.environ["BLUEBOT_API_KEY"])

event = client.events.get("evt_1Hq2LxW9cVbN3mKpRtYs0a")
print(event)
```

## Response

`200`: The event.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | Yes | The event id. A webhook delivery sends it as `webhook-id`, the same on every retry, so a receiver can skip one it already has. Starts with `evt_` |
| `object` | "event" | Yes |   |
| `type` | string | Yes | One of `message.queued`, `message.sent`, `message.delivered`, `message.read`, `message.failed`, `message.unconfirmed`, `message.expired`, `message.canceled`, `message.received`, `message.edited`, `message.unsent`, `reaction.added`, `reaction.removed`, `chat.created`, `contact.created`, `contact.stopped`, `contact.unstopped`, `sequence.completed`, `broadcast.completed`, `automation.matched`, `device.online`, `device.offline`, `device.check_failed` |
| `api_version` | string | Yes | The payload version: the one the receiving webhook was made with. |
| `timestamp` | timestamp | Yes | When it happened. |
| `test` | true | No | Present, and `true`, only on a test event from **Send test event** or `POST /v1/webhooks/{id}/test`. Its `data` is the catalog’s example, with example ids that match nothing on your account. Real events never have it. |
| `data` | map of any | Yes | The record as the API returned it at the time. Each type’s shape is in the event catalog. |

The answer, `200`:

```json
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.received",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
    "object": "message",
    "direction": "in",
    "state": "received",
    "to": "+15555550100",
    "from": "+15555550123",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Perfect, see you there!",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "mac",
    "source_ref": null,
    "metadata": {},
    "hold": null,
    "send_at": null,
    "expires_at": null,
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:44:12.000Z",
    "queued_at": null,
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": "2026-11-13T19:44:10.000Z"
  }
}
```

## Errors

Every refusal has the same envelope and a page of its own. These are the ones this operation can give.

| Code                                                    | Status | What it means                                                                                                                               |
| ------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| [`unauthorized`](https://usebluebot.com/docs/errors/unauthorized)             | 401    | The request carried no key, or a key BlueBot doesn’t know: mistyped, revoked, or a test key sent to the live API.                           |
| [`insufficient_scope`](https://usebluebot.com/docs/errors/insufficient_scope) | 403    | The key doesn’t carry the scope the endpoint needs. Each endpoint’s reference names its scope.                                              |
| [`rate_limited`](https://usebluebot.com/docs/errors/rate_limited)             | 429    | Too many requests. A key may make 120 requests a minute. The `RateLimit` header says how many are left, and `Retry-After` how long to wait. |
| [`internal`](https://usebluebot.com/docs/errors/internal)                     | 500    | Something went wrong on BlueBot’s side. It was reported. Send the request again; with an Idempotency-Key that is always safe.               |
| [`not_found`](https://usebluebot.com/docs/errors/not_found)                   | 404    | There is no such thing on this account. Ids are prefixed by kind, so a message id starts with `msg_`.                                       |

## Try it
