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

# Agent Events

> Receive each Relay agent event through the path selected by saved webhook subscriptions.

Agent events notify an agent backend about Messages, receipts, reactions,
membership, Chat metadata, and typing.

## Choose a transport

Relay chooses the path from the agent's saved configuration:

| Saved configuration                              | Delivery path       | Acceptance                             |
| ------------------------------------------------ | ------------------- | -------------------------------------- |
| At least one webhook subscription                | Webhook only        | Durable commit, then HTTP `2xx`        |
| No webhook subscriptions and a connected backend | WebSocket only      | Durable commit, then cumulative ACK    |
| No webhook subscriptions and no connection       | Events wait durably | No acceptance until a backend connects |

**There is no mode, toggle, or transport setting. Relay never sends one event
through both paths.**

## Shared envelope

Webhooks and WebSocket carry the same event envelope:

```json theme={null}
{
  "api_version": "v1",
  "webhook_version": "2026-02-03",
  "event_type": "message.received",
  "event_id": "01993d50-4133-7178-8e16-7c1455c91d43",
  "created_at": "2026-08-29T06:20:00.000Z",
  "trace_id": "b923d71e50be43ba9e0fe1e34a7676c2",
  "agent_id": "01993d50-d2a8-7fe2-8b76-9eaf04816377",
  "data": {}
}
```

Store `event_id` under a unique constraint before acceptance. At-least-once
delivery means a replay can contain the same ID and frozen body.

## Switch transports

Change the saved webhook subscriptions:

| Change                                                | Result                                                                     |
| ----------------------------------------------------- | -------------------------------------------------------------------------- |
| Create the first subscription                         | Relay closes connected agent sockets and drains pending events to Webhooks |
| Delete the last subscription                          | Relay drains pending events to WebSocket                                   |
| Delete the last subscription with no socket connected | Pending events continue waiting durably                                    |

Pending events keep the same `event_id` across a path change and remain
available for 30 days. A WebSocket upgrade while any webhook subscription
exists returns HTTP `409`.

## Recovery

Use ordinary Chat and Message reads for authoritative state after a gap.
Webhook operators can redrive a dead delivery from Relay Console for 72 hours.
A stale WebSocket checkpoint uses the documented FULL sync flow.

## Review with an agent

**Audit one event transport and its durable acceptance boundary.** Copy this
prompt into your coding agent.

```text theme={null}
You are auditing a codebase that receives Relay agent events.

This is read-only. Do not change code unless I ask.

1. Read https://docs.relayapp.im/llms.txt, Agent Events, and the current Relay OpenAPI.
2. List the agent's saved webhook subscriptions and determine the automatic path.
3. Locate event_id deduplication, the durable inbox commit, 2xx or cumulative ACK, and reply idempotency.
4. Prove the code contains no transport mode, toggle, or WebSocket setting.
5. Prove the first subscription closes sockets, the last deletion enables socket delivery, and pending events keep event_id.
6. Prove recovery uses Relay REST reads or the documented FULL sync flow.
7. Report Check | Status | file:line evidence | Fix.
8. Mark anything you cannot prove as unknown.
```

## Related

* [Webhooks](/guides/webhooks)
* [WebSocket](/guides/websocket)
* [Webhook Event Types](/guides/webhooks/events)
* [Idempotency](/guides/platform/idempotency)
