> 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.

# Webhooks

> Create a webhook endpoint for optional BeatAPI task completion callbacks.

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

Create a webhook endpoint for optional BeatAPI task completion callbacks.

## Authorization

`Authorization`   `string`   **required**

Send your BeatAPI API key as a Bearer token. Create one on the [Dashboard](https://beatapi.io/dashboard).

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

Keep permanent API keys on trusted servers. `Content-Type: application/json` is required for the request body. `Idempotency-Key` is optional when the endpoint exposes it and is recommended for safe retries with the exact same body.

## Request body

`url`   `string`   **required**

Public HTTPS callback URL that accepts BeatAPI task events. Do not use localhost or a private-network URL.

**Format:** `uri`

---

`description`   `string`   **optional**

Optional internal label for identifying the endpoint in your account.

---

`events`   `string[]`   **optional**

Task events to deliver. Omit to subscribe to both `task.succeeded` and `task.failed`.

## Response

A successful request returns 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
  }
}
```

## Verify callback signatures

BeatAPI sends `x-beatapi-event`, `x-beatapi-timestamp`, and `x-beatapi-signature` with every delivery. Compute the expected hex HMAC-SHA256 value over:

`timestamp + "." + raw_request_body`

Use the endpoint `secret` returned by this create request. Compare signatures in constant time, verify the exact raw bytes before JSON parsing, and reject timestamps older than 5 minutes to limit replay attacks.

## Manage endpoints

* `GET /v1/webhooks` lists webhook endpoints.
* `GET /v1/webhooks/{id}` gets a webhook endpoint.
* `PATCH /v1/webhooks/{id}` updates a webhook endpoint.
* `DELETE /v1/webhooks/{id}` deletes a webhook endpoint.

## Next step

Verify every callback signature before parsing its payload. Polling `GET /v1/tasks/{task_id}` remains the source of truth if delivery is delayed or fails.

## Errors

| Status | Meaning                                                                                                                                                                                                                                      |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Malformed JSON or a field, value or combination this endpoint does not accept (`bad_request`; the message names the field), or input refused by moderation (`content_policy_violation`). Not retryable unchanged.                            |
| `401`  | No API key (`missing_api_key`), or a key that is wrong, expired, disabled or exhausted (`invalid_api_key`; the message says which). Send it as `Authorization: Bearer <key>`; the key works with or without the `sk-` prefix. Not retryable. |
| `429`  | Too many requests (`rate_limit_exceeded`, including the free-model limits). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).                                                                                        |
| `500`  | Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.                                                                                                                                       |