> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Вебхуки

> Создайте endpoint вебхука для необязательных уведомлений о завершении задач BeatAPI.

`POST https://api.beatapi.io/v1/webhooks`

Создайте endpoint вебхука для необязательных уведомлений о завершении задач BeatAPI.

## Авторизация

`Authorization`   `string`   **обязательный**

Передавайте API-ключ BeatAPI как токен Bearer. Создать ключ можно в [панели управления](https://beatapi.io/dashboard).

```
Authorization: Bearer <BEATAPI_API_KEY>
```

Храните постоянные API-ключи на доверенных серверах. Для тела запроса обязателен `Content-Type: application/json`. Если метод принимает `Idempotency-Key`, этот заголовок необязателен, но рекомендуется для безопасных повторных попыток с точно таким же телом.

## Тело запроса

`url`   `string`   **обязательный**

Общедоступный HTTPS-адрес для получения событий задач BeatAPI. Не используйте localhost или адрес частной сети.

**Формат:** `uri`

---

`description`   `string`   **необязательный**

Необязательная внутренняя метка для поиска endpoint в вашем аккаунте.

---

`events`   `string[]`   **необязательный**

События задач, которые нужно получать. Если поле не указано, подписка включает `task.succeeded` и `task.failed`.

## Ответ

Успешный запрос возвращает HTTP `201`.

```json
{
  "data": {
    "id": "wh_9aBcD",
    "object": "webhook_endpoint",
    "url": "https://example.com/beatapi-webhook",
    "description": "Production webhook",
    "events": [
      "task.succeeded",
      "task.failed"
    ],
    "status": "active",
    "secret": "whsec_example_store_this_once",
    "created_at": 1782210000,
    "updated_at": 1782210000
  }
}
```

## Проверка подписей уведомлений

При каждой доставке BeatAPI отправляет `x-beatapi-event`, `x-beatapi-timestamp` и `x-beatapi-signature`. Вычислите ожидаемую подпись HMAC-SHA256 в шестнадцатеричном виде для строки:

`timestamp + "." + raw_request_body`

Используйте `secret`, возвращённый при создании endpoint. Сравнивайте подписи за постоянное время, проверяйте точные исходные байты до разбора JSON и отклоняйте временные метки старше 5 минут, чтобы ограничить атаки повторного воспроизведения.

## Управление endpoint вебхуков

* `GET /v1/webhooks` возвращает список endpoint вебхуков.
* `GET /v1/webhooks/{id}` возвращает сведения об endpoint вебхука.
* `PATCH /v1/webhooks/{id}` обновляет endpoint вебхука.
* `DELETE /v1/webhooks/{id}` удаляет endpoint вебхука.

## Следующий шаг

Проверяйте подпись каждого уведомления до разбора его данных. Если доставка задержалась или не состоялась, источником истины остаётся статус из `GET /v1/tasks/{task_id}`.

## Ошибки

| Статус | Значение                                                                                                                                                                                                                                                                   |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Некорректный JSON либо недопустимое поле, значение или сочетание параметров (`bad_request`; сообщение указывает поле), либо входные данные отклонены модерацией (`content_policy_violation`). Повтор без изменений не поможет.                                             |
| `401`  | Ключ не передан (`missing_api_key`), неверен, просрочен, отключён или исчерпал лимит (`invalid_api_key`; точная причина указана в сообщении). Передавайте `Authorization: Bearer <key>`; ключ работает с префиксом `sk-` и без него. Повторять без исправления не следует. |
| `429`  | Слишком много запросов (`rate_limit_exceeded`, в том числе лимит бесплатной модели). Повторите через число секунд из `Retry-After` (также указано в `error.retry_after_seconds`).                                                                                          |
| `500`  | Непредвиденная внутренняя ошибка (`internal_error`). Запрос можно повторить; если ошибка сохраняется, сохраните `request_id` для поддержки.                                                                                                                                |