# Webhooks

Cademí sends an HTTPS `POST` to your endpoint when something happens in your account: a student is created, completes a lesson, passes an exam, receives a certificate. Your endpoint answers with a `2xx` status, and Cademí retries the delivery when it does not.

## Payload versions

Every webhook has a payload version, which decides the body your endpoint receives. Deliveries, retries, and signatures are the same for every version.

| | Version 3 | Version 2 | Version 1 |
|---|---|---|---|
| Status | Current | Older format | Deprecated |
| Events | The API event catalog, such as `lesson_progress.completed` ([Webhooks v3 reference](https://cademi.dev/webhooks/reference.md)) | Dashboard events, such as `course.concluded` ([Webhooks v2 reference](https://cademi.dev/webhooks/v2/reference.md)) | The version 2 events, with names in Portuguese ([Webhooks v1 reference](https://cademi.dev/webhooks/v1/reference.md)) |
| IDs | Public, such as `usr_42` | Numeric | Numeric |
| Personal data | Your choice: IDs only, masked, or full (`payload_detail`) | Always sent | Always sent |
| Events per webhook | Several, with filters by resource | One | One |

## Where to create a webhook

- **In the dashboard**, at **Settings > Integrations > Webhooks**, in any version. See [Set up in the dashboard](https://cademi.dev/webhooks/dashboard.md).
- **Through the API**, with `POST /webhooks`, always version 3. See [API webhooks](https://cademi.dev/api/webhooks.md).

## The body

In version 3, every event carries its `id`, `type`, `version`, `occurred_at`, and the event `data`, with records identified by public ID:

```json
{
  "id": "evt_01J8Z3TESTE",
  "type": "lesson_progress.completed",
  "version": 1,
  "occurred_at": "2026-09-29T12:00:00Z",
  "data": {
    "lesson_id": "les_42",
    "product_id": "prd_42",
    "user_id": "usr_42"
  },
  "delivery_id": "whd_01J8Z3TESTE",
  "attempt": 1
}
```

With `payload_detail` set to `masked` or `full`, the body also carries `expanded`, with the student, product, and lesson ready to use. Each event page lists the full body and every field.

## Receiving events

1. Answer quickly with a `2xx` status, and process the event afterwards. A slow answer counts as a failure and the delivery is retried.
2. Discard repeated deliveries: a retry carries the same event ID.
3. Verify the `Cademi-Signature` header before trusting the body. See [Signatures](https://cademi.dev/webhooks/signatures.md).

See [Deliveries and retries](https://cademi.dev/webhooks/deliveries.md) for timeouts, retries, and the delivery history.
