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

# 웹훅

> BeatAPI 작업 완료 알림(선택 사항)을 받을 웹훅 엔드포인트를 만듭니다.

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

BeatAPI 작업 완료 알림(선택 사항)을 받을 웹훅 엔드포인트를 만듭니다.

## 인증

`Authorization`   `string`   **필수**

BeatAPI API 키를 Bearer 토큰으로 보내세요. 키는 [대시보드](https://beatapi.io/dashboard)에서 만들 수 있습니다.

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

영구 API 키는 신뢰할 수 있는 서버에만 보관하세요. 요청 본문에는 `Content-Type: application/json`이 필요합니다. `Idempotency-Key`는 엔드포인트가 지원하는 경우 선택 사항이며, 완전히 같은 본문으로 안전하게 재시도하려면 사용하는 것이 좋습니다.

## 요청 본문

`url`   `string`   **필수**

BeatAPI 작업 이벤트를 받는 공개 HTTPS 콜백 URL입니다. localhost나 사설 네트워크 URL은 사용하지 마세요.

**형식:** `uri`

---

`description`   `string`   **선택**

계정에서 엔드포인트를 구분하기 위한 내부 라벨입니다(선택 사항).

---

`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`를 보냅니다. 다음 값으로 기대 서명(hex 인코딩한 HMAC-SHA256)을 계산하세요.

`timestamp + "." + raw_request_body`

이 생성 요청이 반환한 엔드포인트 `secret`을 사용하세요. 서명은 상수 시간으로 비교하고, JSON 파싱 전에 정확한 원시 바이트를 검증하며, 재전송 공격을 막기 위해 5분보다 오래된 타임스탬프는 거부하세요.

## 엔드포인트 관리

* `GET /v1/webhooks`는 웹훅 엔드포인트 목록을 조회합니다.
* `GET /v1/webhooks/{id}`는 웹훅 엔드포인트를 조회합니다.
* `PATCH /v1/webhooks/{id}`는 웹훅 엔드포인트를 수정합니다.
* `DELETE /v1/webhooks/{id}`는 웹훅 엔드포인트를 삭제합니다.

## 다음 단계

페이로드를 파싱하기 전에 모든 콜백 서명을 검증하세요. 전달이 지연되거나 실패해도 `GET /v1/tasks/{task_id}` 폴링이 기준 정보입니다.

## 오류

| 상태    | 의미                                                                                                                                                                              |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | JSON 형식이 잘못되었거나, 이 엔드포인트가 받지 않는 필드·값·조합이 있거나(`bad_request`, 메시지에 해당 필드가 표시됨), 입력이 콘텐츠 검수에서 거부되었습니다(`content_policy_violation`). 그대로 재시도할 수 없습니다.                                |
| `401` | API 키가 없거나(`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`를 함께 알려 주세요.                                                                                       |