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

# Webhooks

> Events OlivIA sends to your backend, their payloads, and the delivery policy

**Webhooks** let your backend receive real-time notifications of what happens during calls.

<Info>
  Webhooks **are not registered from the external API**: they are configured in the platform (or with the Omniloy team) and attached to a protocol version. This page documents the events you will receive and how they are delivered.
</Info>

## Events

| Event                | When it fires                           | Filter              |
| -------------------- | --------------------------------------- | ------------------- |
| `session.start`      | When the call session starts            | —                   |
| `session.teardown`   | When the session closes                 | —                   |
| `run.status_changed` | On every questionnaire status change    | `target_statuses[]` |
| `question.answered`  | When an answer is captured              | `question_keys[]`   |
| `call.transferred`   | When the call is transferred to a human | —                   |
| `number.to_verify`   | When a wrong number is detected         | —                   |

## Payloads

The payload is built per event and includes the run and protocol context. Abbreviated examples:

`run.status_changed`:

```json theme={null}
{
  "new_status": "completed",
  "previous_status": "in_progress",
  "run": { "id": "…", "questionnaire_status": "completed", "score": 7, "score_class": "medium" },
  "protocol": { "id": "…", "protocol_key": "seguimiento-epoc", "title": "…" },
  "protocol_version": { "id": "…", "version": 3 },
  "answers": [ { "question_key": "disnea", "answer": "yes" } ],
  "calls": [ { "id": "…", "transcription": [ { "speaker": "patient", "content": "…", "occurred_at": "…" } ] } ]
}
```

`question.answered`:

```json theme={null}
{ "question_key": "disnea", "answer": "yes" }
```

<Note>
  Payloads do not include patient personal data unless the event explicitly requires it (e.g. `number.to_verify`, which carries `patient_id` and `phone`). To link a run to a patient, join on `run.enrollment_id`.
</Note>

## Authentication to your endpoint

OlivIA **does not sign the body with HMAC**. Instead, each webhook authenticates **against your endpoint** with the credentials you configure. Options:

| Type                        | Effect                                               |
| --------------------------- | ---------------------------------------------------- |
| `bearer`                    | `Authorization: Bearer <token>`                      |
| `basic`                     | `Authorization: Basic <base64>`                      |
| `api_key`                   | Custom header `<header_name>: <value>`               |
| `oauth2_client_credentials` | OlivIA fetches a token from `token_url` and sends it |

Secrets are encrypted at rest (AES-256-GCM) and shown masked. Protect your endpoint by validating these credentials.

## Delivery and retries

* **Best-effort** delivery; every attempt is recorded.
* Configurable retries: `max_retries` (0–10) and `timeout_ms` (100–60000, default 10000).
* Retried on network errors, timeouts, and `5xx` responses. Not retried on `4xx`. Redirects are **not** followed.
