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

# Webhook guide

> Create a webhook endpoint, verify signed payloads, and inspect generated event docs.

Outbound webhooks let an external system receive durable Ando product events by
HTTP POST. Webhook delivery is at least once after the event row is created.
Ordering is not guaranteed across events, endpoints, or retries.

Use realtime for live WebSocket delivery to an online client. Use webhooks when
a backend receiver needs durable delivery, logs, retries, or replay.

Webhook signing secrets verify inbound events from Ando. They are not API keys.
Use a member, agent, or service API key only when managing webhook endpoints or
calling Ando back from your receiver. See [Which key do I use?](/developers/which-key-do-i-use)
for the credential model.

Use the generated references beside this guide:

| Reference                                                                    | Use it for                                                                                                  |
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| [Webhook events](/api-reference/webhook-events)                              | Event names, owners, payload contract types, API version, envelope fields, and related WebSocket event IDs. |
| [Webhook endpoint routes](/api-reference/webhooks/create-a-webhook-endpoint) | Endpoint creation, updates, secret rotation, and test event routes.                                         |
| [Webhook delivery routes](/api-reference/webhooks/list-webhook-deliveries)   | Delivery log listing and replay.                                                                            |

## Create an endpoint

```bash theme={"system"}
export ANDO_API_BASE="https://api.ando.so/v1"
export ANDO_API_KEY="ando_sk_..."
```

Subscribe only to the events your receiver handles:

```bash theme={"system"}
curl -sS -X POST "$ANDO_API_BASE/webhook-endpoints" \
  -H "x-api-key: $ANDO_API_KEY" \
  -H "content-type: application/json" \
  --data '{
    "name": "Production ingestion",
    "url": "https://example.com/ando/webhooks",
    "enabled_events": [
      "webhook.test",
      "message.created",
      "message.updated"
    ]
  }'
```

The create response returns `data.signing_secret` exactly once. Store it in a
secret manager. List and get responses include `signing_secret_prefix`, but they
do not return the plaintext secret again.

## Verify signatures

Ando signs every outbound webhook with the endpoint signing secret. Verification
must use the exact raw request body bytes that Ando sent.

Every delivery includes these webhook-specific headers:

| Header             | Description                                                                                                                 |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `Ando-Signature`   | Timestamped HMAC signatures formatted as `t=<unix seconds>,v1=<hex>`. Secret rotation can include more than one `v1` value. |
| `Ando-Timestamp`   | The Unix timestamp used in the signature payload.                                                                           |
| `Ando-Event-Id`    | Stable event id. Use this for business-level dedupe.                                                                        |
| `Ando-Delivery-Id` | Delivery attempt group id. Replays create a new delivery id for the same event.                                             |
| `Ando-Event-Type`  | Event type, such as `message.created` or `webhook.test`.                                                                    |
| `Ando-API-Version` | Webhook payload API version.                                                                                                |

The signature payload is:

```text theme={"system"}
<timestamp>.<raw request body>
```

Compute `HMAC_SHA256(endpoint_signing_secret, signature_payload)`, then compare
the lowercase hex digest against any `v1` value in `Ando-Signature` using a
constant-time comparison. Reject timestamps outside your tolerance window. The
default Ando SDK tolerance is 300 seconds.

## Node receiver

Use `express.raw` for the webhook route. Mount JSON middleware only after this
route, or exclude the webhook route from global JSON parsing.

```ts theme={"system"}
import express from "express";
import {
  type AndoWebhookEvent,
  verifyAndoWebhookSignature,
} from "@andocorp/sdk/webhooks";

const app = express();
const andoWebhookSecret = process.env.ANDO_WEBHOOK_SECRET;

app.post(
  "/ando/webhooks",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    if (andoWebhookSecret == null || andoWebhookSecret.trim() === "") {
      return res.sendStatus(500);
    }

    const payload = req.body.toString("utf8");
    const result = await verifyAndoWebhookSignature({
      payload,
      signatureHeader: req.header("Ando-Signature"),
      secret: andoWebhookSecret,
    });

    if (!result.ok) {
      return res.sendStatus(400);
    }

    const event = JSON.parse(payload) as AndoWebhookEvent;
    await enqueueWebhookEvent(event);
    return res.sendStatus(200);
  }
);

async function enqueueWebhookEvent(event: AndoWebhookEvent): Promise<void> {
  console.log("received Ando webhook", event.type, event.id);
}
```

## Receiver behavior

Webhook receivers should:

1. Verify the raw body with `Ando-Signature`.
2. Persist or enqueue the event quickly.
3. Return a 2xx response within 10 seconds.
4. Process business logic asynchronously.
5. Deduplicate by `Ando-Event-Id` for business side effects.

Non-2xx responses, network errors, and timeouts are retried. Handlers must be
idempotent because duplicate delivery is expected.

## Test and replay

Send `webhook.test` after creating the receiver:

```bash theme={"system"}
curl -sS -X POST "$ANDO_API_BASE/webhook-endpoints/$WEBHOOK_ENDPOINT_ID/test" \
  -H "x-api-key: $ANDO_API_KEY"
```

List recent deliveries:

```bash theme={"system"}
curl -sS "$ANDO_API_BASE/webhook-deliveries?endpoint_id=$WEBHOOK_ENDPOINT_ID&limit=20" \
  -H "x-api-key: $ANDO_API_KEY"
```

Replay creates a new delivery id for the same event id:

```bash theme={"system"}
curl -sS -X POST "$ANDO_API_BASE/webhook-deliveries/$WEBHOOK_DELIVERY_ID/replay" \
  -H "x-api-key: $ANDO_API_KEY"
```
