# 인증 Webhook (/docs/webhooks/verification)

인증 Webhook 은 [Verify API](/docs/api-reference) 로 시작한 인증 한 건의 결과를 알립니다.
계정 레벨에서 REST API 로 등록합니다.

**인증번호(코드)는 `verification.*` 페이로드에 실리지 않습니다.** 대조는 한국AI통신이 끝내므로
수신측이 코드를 받아 할 일이 없습니다.

⚠️ 다만 **수신형(`sms_inbound`)은 사용자가 보낸 문자 자체가 고객님의 수신 문자**입니다.
그 본문에는 코드가 들어 있고, 원장(`messages`)에 남고 `message.received` Webhook 으로도
그대로 전달됩니다 — 인증에 쓰였다고 빼면 받은 문자와 기록이 달라지기 때문입니다.
로그 접근 권한을 그에 맞게 잡아 주세요.

### 등록

```
POST /v1/accounts/{accountId}/webhooks

Body:
{
  "url": "https://my-app.com/verification-webhook",
  "events": ["verification.verified", "verification.failed", "verification.expired"]
}
```

## 이벤트 종류

- `verification.verified` (event, 선택): 사용자가 코드를 맞게 입력해 인증이 통과함
- `verification.failed` (event, 선택): 전달 자체가 실패해 그 건이 failed 로 닫힘 — 문자 발송 실패, 또는 통화 미응답·실패
- `verification.expired` (event, 선택): ttlSeconds 안에 완료되지 않아 만료됨

`POST /v2/verifications/{id}/check` 는 통과 여부를 곧바로 응답으로 돌려주므로, 발신형
(`sms`·`call`)만 쓴다면 Webhook 없이도 결과를 알 수 있습니다. 다만 `call` 의 **미응답은
`check` 로 알 수 없습니다** — 전화를 받지 않은 건은 `verification.failed` 로만 통지되므로,
재시도 안내를 띄우려면 등록하는 편이 낫습니다.

**수신형(`sms_inbound`)은 Webhook 이 주 경로입니다.** 사용자가 입력할 것이 없어 `check` 를
부를 수 없기 때문입니다(부르면 `422 check_not_supported`).

사용자가 문자를 **보내지 않은** 경우는 `verification.expired` 가 곧바로 오지 않습니다 —
응답의 `instruction.deadline` 까지 `verification.verified` 가 오지 않으면 실패로 처리하십시오.
`verification.expired` 는 그 건을 조회하는 시점에 확정됩니다.

`from` 은 **문자를 받아 본 적 있는 번호로 지정**하시는 편이 안전합니다. 생략하면 계정 번호
중 하나가 자동으로 잡히는데, 갓 발급받은 번호는 수신이 아직 열리지 않았을 수 있습니다.

## 요청 파라미터

모든 요청은 `Content-Type: application/x-www-form-urlencoded` POST 입니다.

- `Event` (string, 필수): verification.verified / verification.failed / verification.expired
- `AccountId` (string, 필수): 계정 ID
- `VerificationId` (string, 필수): 인증 건 ID (VE...)
- `Channel` (string, 필수): 인증 방식 — sms, call, sms_inbound
- `To` (string, 필수): 인증 대상 번호
- `VerifiedAt` (string, 선택): 통과 시각 (ISO 8601). verification.verified 에만 실립니다.
- `Reason` (string, 선택): failed·expired 의 사유 코드. 예: send_failed, ttl_elapsed, call_no-answer, call_busy
- `Timestamp` (string, 필수): 이벤트 발생 시각 (ISO 8601)


```
Event=verification.verified&AccountId=ACxxx&VerificationId=VE1a2b3c4d5e6f7a8b
&Channel=sms&To=01012345678&VerifiedAt=2026-09-18T04:00:12.345Z
&Timestamp=2026-09-18T04:00:12.350Z
```

## 예제

```python
from flask import Flask, request

app = Flask(__name__)

@app.route("/verification-webhook", methods=["POST"])
def verification_webhook():
    event = request.form.get("Event")
    verification_id = request.form.get("VerificationId")

    if event == "verification.verified":
        mark_phone_verified(verification_id, request.form.get("To"))
    else:
        # failed·expired 는 사용자가 다시 시도하게 두면 됩니다.
        clear_pending_verification(verification_id)

    return "", 204
```


이 요청에도 `X-Signature` 헤더가 포함됩니다. [서명 검증 가이드](/docs/webhooks/signature-verification)를
참고하여 요청의 무결성을 확인하세요.

