
# 웹훅 엔드포인트 추가

`POST /v1/webhook-endpoints` · 권한 `webhook-endpoints:write` · 모든 요금제

환경의 이벤트를 받는 엔드포인트를 추가합니다. 이벤트는 Standard Webhooks v1 방식으로 서명됩니다. 전달은 최소 한 번 이루어지므로 `webhook-id` 헤더로 중복을 제거하십시오.

- **서명 비밀 값.** 응답에는 `signing_secret`(`idp_whsec_…`)이 한 번만 포함되며, 응답은 `Cache-Control: no-store`로 전달됩니다. 이 값은 다시 조회할 수 없으므로 즉시 저장하십시오. 같은 `Idempotency-Key`로 요청을 반복하면 비밀 값 없이 `secret_redacted: true`가 포함된 엔드포인트가 반환됩니다. 분실하였거나 유출된 경우 [서명 비밀 값 교체](rotate-secret.md)를 사용하십시오.
- **URL.** `https`만 허용되며, 포트는 없거나 443이어야 합니다. 사용자 정보나 fragment를 포함할 수 없고, IP 리터럴을 사용할 수 없으며, 최대 2,048자입니다. 리디렉션은 따라가지 않습니다.
- **이벤트.** `event_types`에는 카탈로그의 이벤트 유형을 나열합니다. 목록이 비어 있으면 대량 발생 유형을 제외한 모든 유형이 대상이 됩니다.
- **한도.** 환경당 활성화된 엔드포인트는 Free 3개, Startup 20개, Business 20개, Enterprise 50개까지 만들 수 있습니다.

## 요청

| 필드 | 유형 | 필수 | 설명 |
|---|---|---|---|
| `url` | string | 예 | 수신 URL(위 규칙 적용). |
| `key` | string | 아니요 | 환경 내에서 고유한 고정 키: `[a-z0-9][a-z0-9_-]{0,63}`. 기본값은 `endpoint-<id의 마지막 8자>`. |
| `description` | string | 아니요 | 최대 500자. |
| `event_types` | array | 아니요 | 카탈로그 이벤트 유형, 최대 100개, 중복 불가. 비어 있거나 생략하면 대량 발생 유형을 제외한 모든 유형. |
| `event_schema_versions` | object | 아니요 | 이벤트 유형 → 스키마 버전. 나열되지 않은 유형은 지원되는 가장 오래된 버전으로 전송됩니다. |
| `payload_mode` | string | 아니요 | `thin`(기본값: ID, 변경된 필드 이름과 상태 필드, 개인 데이터 없음) 또는 `full`(리소스의 관리 API 표현). |
| `rate_limit_per_second` | integer | 아니요 | 이 엔드포인트로의 초당 전달 수 1–1,000; 기본값 50. |
| `status` | string | 아니요 | `enabled`(기본값) 또는 `disabled_by_user`. |
| `Idempotency-Key` | header | 아니요 | 같은 키로 반복된 요청에 대해 응답(비밀 값 제외)을 재생합니다. |

```json
{
  "url": "https://hooks.example.com/keenauth",
  "key": "crm-sync",
  "description": "CRM sync",
  "event_types": ["user.created", "user.updated"]
}
```

## 응답

`201 Created`와 함께 엔드포인트, 버전을 나타내는 `ETag`, 서명 비밀 값이 반환됩니다. 나머지 필드는 [웹훅 엔드포인트 조회](get.md)에 설명되어 있습니다.

```json
{
  "id": "whe_01k8a3m5q7t9v1w3x5y7z9b2c4",
  "key": "crm-sync",
  "url": "https://hooks.example.com/keenauth",
  "description": "CRM sync",
  "event_types": ["user.created", "user.updated"],
  "event_schema_versions": {},
  "payload_mode": "thin",
  "status": "enabled",
  "rate_limit_per_second": 50,
  "previous_secret_expires_at": null,
  "last_success_at": null,
  "failing_since": null,
  "version": 1,
  "created_at": "2026-10-26T09:00:00Z",
  "updated_at": "2026-10-26T09:00:00Z",
  "signing_secret": "idp_whsec_<secret>"
}
```

## 오류

| HTTP | code | 발생 조건 |
|---|---|---|
| 400 | `unknown_field` | 본문에 위에 나열되지 않은 필드가 있습니다. |
| 403 | `quota_exceeded` | 환경이 이미 요금제에서 허용하는 활성 엔드포인트 수에 도달했거나, 요금제를 확인할 수 없습니다. |
| 409 | `conflict` | 같은 환경의 다른 엔드포인트가 이 `key`를 사용하고 있습니다. |
| 422 | `validation_failed` | `/url required`, `/url invalid_webhook_url`, `/key invalid`, `/description too_long`, `/event_types unknown_event_type`, `/event_types duplicate`, `/event_types too_many`, `/event_schema_versions unsupported_schema_version`, `/payload_mode invalid`, `/rate_limit_per_second out_of_range`, `/status invalid`. |
| 422 | `idempotency_key_reuse` | 다른 요청에 이미 사용된 `Idempotency-Key`를 사용했습니다. |
| 401 | `unauthenticated` | 자격 증명이 없거나 잘못되었거나 취소되었습니다. |
| 403 | `insufficient_permissions` | 자격 증명에 `webhook-endpoints:write` 권한이 없습니다. |
| 429 | `rate_limited` | 요청 한도를 초과했습니다. `Retry-After` 기간 이후에 다시 시도하십시오. |
| 503 | `service_unavailable` | 웹훅 관리 기능을 일시적으로 사용할 수 없습니다. `Retry-After` 기간 이후에 다시 시도하십시오. |

## 예제

```bash
curl -X POST https://api.eu.keenauth.com/v1/webhook-endpoints \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9b2d4f6a-1c3e-4a5b-8d7f-0e2c4a6b8d1f" \
  -d '{"url":"https://hooks.example.com/keenauth","key":"crm-sync","event_types":["user.created","user.updated"]}'
```

CLI: `keenauth webhook-endpoints create --url https://hooks.example.com/keenauth --key crm-sync --event-types user.created,user.updated`
