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

# Configure Webhooks for Message Delivery Events

> Set up a RelayOS webhook endpoint to receive real-time delivery status updates as your WhatsApp messages move through the delivery pipeline.

Webhooks let RelayOS push delivery status updates to your server the moment they happen, instead of requiring you to poll `GET /v1/messages/{id}`. Each time a message changes status — sent, delivered, read, or failed — RelayOS sends an HTTP `POST` request to the `callbackUrl` you configure on your project. Your endpoint receives a JSON payload describing the event and can use it to update your database, trigger follow-up logic, or surface delivery confirmation to your users.

## Configure your callback URL

Set your `callbackUrl` by calling `PUT /v1/projects/me/meta-credentials`. You can include it alongside your Meta credentials or update it on its own at any time.

```bash theme={null}
curl -X PUT https://api.relayos.com.br/v1/projects/me/meta-credentials \
  -H "Authorization: Bearer rly_live_xxx..." \
  -H "Content-Type: application/json" \
  -d '{
    "metaPhoneNumberId": "SEU_PHONE_NUMBER_ID",
    "metaAccessToken": "SEU_ACCESS_TOKEN",
    "callbackUrl": "https://seusite.com.br/relayos-webhook"
  }'
```

Your endpoint must be publicly reachable over HTTPS. RelayOS will start delivering events to it immediately after the credential update is saved.

## Webhook event payload

Every event RelayOS sends has the same JSON structure. The `event` field tells you which status transition occurred, and `message_id` lets you correlate the event to the original message.

```json theme={null}
{
  "event": "message.delivered",
  "message_id": "msg_01hwz3k8j2fxqbv9r4tp6d",
  "to": "+5511999998888",
  "template": "lembrete_consulta",
  "status": "DELIVERED",
  "meta_message_id": "wamid.HBgLNTUxMTk5OTk5ODg4FQIAERgSM...",
  "occurred_at": "2026-05-14T14:22:10Z"
}
```

### Payload fields

<ResponseField name="event" type="string" required>
  The type of event that occurred. See the [event types table](#event-types) below.
</ResponseField>

<ResponseField name="message_id" type="string" required>
  The RelayOS message ID returned when you called `POST /v1/messages`. Use this to match events to messages in your system.
</ResponseField>

<ResponseField name="to" type="string" required>
  The recipient phone number in E.164 format.
</ResponseField>

<ResponseField name="template" type="string" required>
  The name of the template used for this message.
</ResponseField>

<ResponseField name="status" type="string" required>
  The new status of the message after this event. Mirrors the `event` field in upper-case noun form: `SENT`, `DELIVERED`, `READ`, or `FAILED`.
</ResponseField>

<ResponseField name="meta_message_id" type="string" required>
  The opaque message ID assigned by Meta's WhatsApp Cloud API (`wamid.*`). Useful for support escalations.
</ResponseField>

<ResponseField name="occurred_at" type="string" required>
  ISO 8601 UTC timestamp of when the status change occurred.
</ResponseField>

## Event types

| Event               | Triggered when                                                               |
| ------------------- | ---------------------------------------------------------------------------- |
| `message.sent`      | Meta confirmed the message left their servers toward the recipient's device. |
| `message.delivered` | The message arrived on the recipient's device.                               |
| `message.read`      | The recipient opened the message (requires read receipts to be enabled).     |
| `message.failed`    | All delivery attempts failed after exponential backoff retries.              |

## Request headers RelayOS sends

RelayOS includes the following headers on every webhook `POST` so your server can identify and deduplicate events:

| Header               | Value                    | Description                                                                            |
| -------------------- | ------------------------ | -------------------------------------------------------------------------------------- |
| `X-RelayOS-Event`    | e.g. `message.delivered` | The event type, matching the `event` field in the payload.                             |
| `X-RelayOS-Delivery` | UUID string              | A unique identifier for this specific delivery attempt. Use it to deduplicate retries. |
| `User-Agent`         | `RelayOS/1.0`            | Identifies the sender as the RelayOS platform.                                         |

## Handle and acknowledge events

Your endpoint must respond with any `2xx` HTTP status code within a reasonable time. RelayOS considers any other response — including `3xx` redirects, `4xx` errors, `5xx` errors, or a timeout — a failed delivery and will retry.

```json theme={null}
HTTP/1.1 200 OK
```

<Tip>
  Return `200` immediately after receiving the request, then process the payload asynchronously. If your handler does slow database writes or calls external APIs synchronously, it risks timing out and triggering unnecessary retries. RelayOS retries failed deliveries with exponential backoff, so your endpoint may receive the same event more than once — use `X-RelayOS-Delivery` to deduplicate.
</Tip>
