> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# 전화번호 인증 보고서: OTP 및 통신사 JSON

> Didit 전화번호 인증 응답 파싱 가이드: 통신사 데이터, 회선 유형, OTP 수명 주기, 세션 간 일치 및 위험 경고를 확인하세요. 통신사 요금 외 OTP당 $0.02부터 제공됩니다.

전화번호 인증 보고서는 전화번호 OTP 챌린지의 전체 결과를 캡처합니다. 코드를 전송한 대상, 이를 처리한 통신사 및 채널, 시도 횟수, 번호가 일회용인지 또는 VoIP인지 여부, 차단 목록 또는 다른 사용자의 세션과의 교차 세션 일치 여부 등이 포함됩니다.

이 페이지에서는 인증된 각 번호에 대한 OTP 결과, 통신사 메타데이터, 위험 플래그를 파싱할 수 있도록 결정 endpoint가 반환하는 JSON 형태를 설명합니다.

![OTP 결과, 통신사 메타데이터 및 위험 플래그를 보여주는 Didit 전화번호 인증 보고서](https://mintcdn.com/didit-0f962782/z6T2GHM4Zh-iSj-K/images/phone-verification-report.png?fit=max\&auto=format\&n=z6T2GHM4Zh-iSj-K\&q=85\&s=9b5c6c6112303ebc60c0f287aafdb996)

## 개요

워크플로 노드가 전화번호 인증 기능을 실행할 때마다 전화번호 보고서가 생성됩니다. 각 보고서는 하나의 전화번호에 대한 한 번의 OTP 챌린지를 나타내며 다음을 포함합니다.

* 접두사, 국내 번호 및 전체 E.164 형식으로 분할된 전화번호와 ISO 국가 코드 및 국가명.
* 대상 네트워크에서 확인된 통신사 메타데이터(`name`, `type`).
* 회선 유형 분석에서 도출된 불리언 위험 플래그(`is_disposable`, `is_virtual`).
* 사용된 실제 전송 채널(`verification_method`) 및 OTP 전송 시도 횟수.
* 모든 전송, 재시도, 전송 이벤트 및 코드 확인 시도에 대한 시간순 `lifecycle[]` 로그.
* 다른 세션(KYC, KYB 및 독립형 API 인증 전반의 모든 상태) 또는 차단 목록에 동일한 번호가 있는지 나타내는 `matches[]` 배열.
* `warnings[]` 배열 — 인증 도중 발생한 위험 이벤트([전화번호 인증 경고](https://docs.didit.me/ko/core-technology/phone-verification/warnings-phone-verification.md) 참조).
* 보고서를 생성한 워크플로 그래프 노드를 식별하는 `node_id`(V3 세션 전용).

호스팅 인증 플로우에서는 Didit이 대신 OTP 교환을 처리합니다. 직접 API 연동의 경우 동일한 플로우가 두 번의 호출로 이루어집니다. 코드를 전송하는 [`POST /v3/phone/send/`](https://docs.didit.me/ko/standalone-apis/phone-send)와 사용자가 입력한 값을 검증하는 [`POST /v3/phone/check/`](https://docs.didit.me/ko/standalone-apis/phone-check)입니다. 대기 중인 OTP는 **최초 전송 후 5분간** 유효합니다(재시도해도 유효 기간이 연장되지 않습니다). 워크플로 세션에서 사용자는 기본적으로 2회의 OTP 전송 시도(`phone_max_retries`)와 2회의 코드 입력 시도(`phone_max_check_attempts`)를 할 수 있으며, 둘 다 워크플로 노드별로 조정할 수 있습니다. 두 한도 중 하나라도 소진되면 해당 단계는 `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`와 함께 `Declined`로 완료됩니다. 독립형 전화번호 API는 인증 건당 3회의 코드 입력 시도를 허용합니다.

## API 응답에서 표시되는 위치

결정 endpoint(`GET /v3/session/{sessionId}/decision/`)는 복수형 배열 키인 **`phone_verifications`** 아래에 전화번호 보고서를 반환합니다. 이 배열에는 워크플로 그래프의 전화번호 인증 노드당 하나의 항목이 포함되며, 일반적으로 하나이지만 단계별 강화 플로우에서는 여러 개가 생성될 수 있습니다.

```json theme={null}
{
  "session_id": "11111111-1111-1111-1111-111111111111",
  "status": "Approved",
  "phone_verifications": [
    { "status": "Approved", "node_id": "feature_phone_1", "...": "..." }
  ]
}
```

`null` 값은 전화번호 인증 단계가 아직 실행되지 않았음을 의미합니다. 워크플로에서 둘 이상의 전화번호를 수집할 수 있는 경우, `phone_verifications[0]`을 바로 읽기보다는 배열을 순회하십시오.

## 스키마

표준 필드별 스키마는 [데이터 모델](https://docs.didit.me/ko/reference/data-models.md#전화번호-인증) 페이지에 있습니다.

```typescript theme={null}
interface PhoneVerification {
  status: "Not Finished" | "Approved" | "Declined" | "In Review" | "Expired";
  phone_number_prefix: string;       // E.g. "+34"
  phone_number: string;              // National number, no prefix
  full_number: string;               // Full E.164, e.g. "+34600600600"
  country_code: string;              // ISO 3166-1 alpha-2, e.g. "ES"
  country_name: string;
  carrier: {
    name: string;
    type:                              // From LineTypeChoices
      | "mobile" | "fixed_line" | "voip" | "isp" | "vpn"
      | "toll_free" | "premium_rate" | "shared_cost" | "local_rate"
      | "satellite" | "pager" | "payphone" | "voice_mail"
      | "calling_cards" | "service" | "short_codes_commercial"
      | "universal_access" | "other" | "unknown";
  };
  is_disposable: boolean;            // Temporary / burner number
  is_virtual: boolean;               // true when carrier.type is voip, isp or vpn
  verification_method:               // Actual channel that delivered the OTP
    | "sms" | "whatsapp" | "telegram" | "voice" | "rcs" | "viber" | "zalo";
  verification_attempts: number;     // OTP send attempts (initial send + resends)
  verified_at: string | null;        // ISO 8601, set when a valid OTP was entered
  warnings: Warning[];               // Risk events emitted during verification
  lifecycle: PhoneLifecycleEvent[];  // OTP send/retry/delivery/check timeline
  matches: PhoneMatch[];             // Cross-session / blocklist matches (max 5)
  node_id: string;                   // Workflow graph node that produced this report
}
```

### 상태 값

| 상태 | 의미 |
| - | - |
| `Not Finished` | OTP 발송이 시작되었으나 아직 인증이 완료되지 않았습니다. |
| `Approved` | 사용자가 유효한 OTP를 입력했으며 거부 대상 위험이 일치하지 않았습니다. |
| `Declined` | 자동 거부 경고가 발생했거나(차단 목록, 고위험, 시도 횟수 초과), `DECLINE`으로 구성된 위험 작업이 일치했습니다. |
| `In Review` | `REVIEW`로 구성된 위험 작업으로 인해 해당 단계가 수동 검토로 라우팅되었습니다. |
| `Expired` | 유효한 코드 없이 5분의 OTP 유효 시간이 경과했습니다. 독립형 전화번호 API를 통해 생성된 인증에 적용됩니다. |

### 수명 주기 이벤트 유형

`lifecycle[]`는 시간순으로 정렬됩니다. 각 이벤트에는 `type`, `timestamp`, `details` 및 청구 가능한 `fee`(해당하는 경우)가 포함됩니다.

| 이벤트 유형 | 발생 시점 |
| - | - |
| `PHONE_VERIFICATION_MESSAGE_SENT` | 요청된 채널을 통한 첫 번째 OTP 발송 시도 시. |
| `PHONE_VERIFICATION_RETRY_MESSAGE_SENT` | 사용자의 재전송 요청 후 후속 OTP 발송 시. |
| `PHONE_VERIFICATION_BLOCKED` | 발송이 차단된 경우(스팸, 의심스러운 활동, 반복 시도, 유효하지 않은 번호). |
| `PHONE_DELIVERY_DELIVERED` | 통신사가 실제 사용된 채널로의 전달을 확인한 경우. |
| `PHONE_DELIVERY_UNDELIVERABLE` | 통신사에서 메시지가 전달되지 않았다고 보고한 경우. |
| `VALID_CODE_ENTERED` | 사용자가 올바른 OTP 코드를 제출한 경우. |
| `INVALID_CODE_ENTERED` | 사용자가 잘못된 OTP 코드를 제출한 경우(코드 입력 한도에 반영됨). |
| `PHONE_VERIFICATION_APPROVED` | 기능 수준 상태가 `Approved`로 설정된 경우. |
| `PHONE_VERIFICATION_DECLINED` | 기능 수준 상태가 `Declined`로 설정된 경우. |
| `PHONE_VERIFICATION_IN_REVIEW` | 기능 수준 상태가 `In Review`로 설정된 경우. |
| `PHONE_VERIFICATION_EXPIRED` | 유효한 코드 없이 OTP 유효 시간이 경과한 경우. |

`details` payload는 이벤트 제품군에 따라 다릅니다.

* **발송 이벤트** (`PHONE_VERIFICATION_MESSAGE_SENT`, `PHONE_VERIFICATION_RETRY_MESSAGE_SENT`, `PHONE_VERIFICATION_BLOCKED`) — `{ status, reason, channel, actual_channel }`. `status`는 `Success`, `Retry`, `Blocked` 중 하나입니다. `reason`은 발송이 차단된 경우(`invalid_phone_number`, `repeated_attempts`, `suspicious`, `spam`, `unknown`)를 제외하고 `null`입니다. `channel`은 요청된 채널이며, `actual_channel`은 실제로 전송된 채널(예: SMS로 대체된 WhatsApp 발송)입니다.
* **전송 이벤트** (`PHONE_DELIVERY_DELIVERED`, `PHONE_DELIVERY_UNDELIVERABLE`) — `{ channel, status }`이며 `status`는 `delivered` 또는 `undeliverable`입니다.
* **확인 이벤트** (`VALID_CODE_ENTERED`, `INVALID_CODE_ENTERED`) — `{ code_tried, status }`이며 `status`는 `Approved`, `Declined`, `Failed`, `Expired or Not Found` 중 하나입니다.
* **최종 상태 이벤트** — `null`이지만, `PHONE_VERIFICATION_DECLINED` / `PHONE_VERIFICATION_IN_REVIEW`는 예외적으로 `{ "reason": "<risk code>" }`(예: `PHONE_NUMBER_IN_BLOCKLIST`)를 포함합니다.

발송 이벤트의 `fee`는 해당 발송의 총 가격입니다. 즉, 통신사 또는 WhatsApp 요금에 Didit 수수료 $0.02를 더한 금액이거나, [자체 WhatsApp Business 번호](https://docs.didit.me/ko/core-technology/phone-verification/overview.md#자체-번호로-whatsapp-코드-발송)에서 전송된 WhatsApp 코드의 경우 Didit 수수료 $0.02만 부과됩니다. 전달이 확인될 때까지는 예상 가격이며, 전달이 확인되면 실제 청구 금액이 됩니다. `Blocked` 발송만 무료가 보장됩니다. 전송이 확인되지 않았거나 메시지를 전송할 수 없었던 경우에도 다른 모든 발송은 인증이 완료되거나 만료될 때 요금이 청구됩니다. 전송, 확인 및 상태 이벤트는 항상 `fee: 0`입니다.

### 세션 간 일치 항목

`matches[]`는 상태와 관계없이 KYC, KYB 및 독립형 API 인증 전반에서 동일한 번호가 확인된 동일 애플리케이션 내의 다른 세션과 [Management API 목록](https://docs.didit.me/ko/management-api/lists/overview.md)에 구성된 차단 목록 일치 항목을 기록합니다. 현재 세션의 `vendor_data`를 공유하는 세션은 제외되며(동일한 최종 사용자는 자신과 일치하지 않음), 배열은 최대 **5**개 항목으로 제한됩니다. 해당 번호가 차단 목록에 있지만 일치하는 세션 중 차단 목록에 포함된 세션이 없는 경우, `source: "list_entry"`(모든 세션 필드는 `null`)를 가진 합성 항목이 배열의 맨 앞에 추가됩니다.

```typescript theme={null}
interface PhoneMatch {
  session_id: string | null;         // null when source = "list_entry"
  session_number: number | null;
  vendor_data: string | null;
  verification_date: string | null;  // ISO 8601, creation date of the matched session
  phone_number: string;
  status: string | null;             // Status of the matched session
  is_blocklisted: boolean;
  api_service: string | null;        // Set when the matched session came from a standalone API
  source: "session" | "list_entry";  // "list_entry" = manual blocklist hit
}
```

## 예시

### 승인됨 — WhatsApp OTP, 모바일 통신사

```json theme={null}
{
  "status": "Approved",
  "phone_number_prefix": "+34",
  "phone_number": "600600600",
  "full_number": "+34600600600",
  "country_code": "ES",
  "country_name": "Spain",
  "carrier": { "name": "Orange", "type": "mobile" },
  "is_disposable": false,
  "is_virtual": false,
  "verification_method": "whatsapp",
  "verification_attempts": 1,
  "verified_at": "2025-08-24T09:12:39.684292Z",
  "warnings": [],
  "lifecycle": [
    {
      "type": "PHONE_VERIFICATION_MESSAGE_SENT",
      "timestamp": "2025-08-24T09:12:30.580554Z",
      "details": { "status": "Success", "reason": null, "channel": "whatsapp", "actual_channel": "whatsapp" },
      "fee": 0.0509
    },
    {
      "type": "PHONE_DELIVERY_DELIVERED",
      "timestamp": "2025-08-24T09:12:31.000000Z",
      "details": { "channel": "whatsapp", "status": "delivered" },
      "fee": 0
    },
    {
      "type": "VALID_CODE_ENTERED",
      "timestamp": "2025-08-24T09:12:39.662157Z",
      "details": { "code_tried": "123456", "status": "Approved" },
      "fee": 0
    },
    {
      "type": "PHONE_VERIFICATION_APPROVED",
      "timestamp": "2025-08-24T09:12:39.684292Z",
      "details": null,
      "fee": 0
    }
  ],
  "matches": [],
  "node_id": "feature_phone_1"
}
```

### 거부됨 — 차단 목록에 등록된 VoIP 번호

사용자가 유효한 OTP를 입력했으나 완료 시 해당 번호가 애플리케이션의 차단 목록에서 발견되어(자동 거부) VoIP 회선 유형 플래그가 지정되었습니다(`voip_number_action`이 `NO_ACTION`으로 유지되어 `information`으로 기록됨). 일치하는 세션 중 차단 목록에 포함된 세션이 없으므로, 차단 목록 일치 항목은 합성 `list_entry` 일치 항목으로 표시됩니다.

```json theme={null}
{
  "status": "Declined",
  "phone_number_prefix": "+1",
  "phone_number": "5551234567",
  "full_number": "+15551234567",
  "country_code": "US",
  "country_name": "United States",
  "carrier": { "name": "VoIP Carrier", "type": "voip" },
  "is_disposable": false,
  "is_virtual": true,
  "verification_method": "sms",
  "verification_attempts": 1,
  "verified_at": "2025-08-24T09:11:10.221340Z",
  "warnings": [
    {
      "feature": "PHONE",
      "risk": "PHONE_NUMBER_IN_BLOCKLIST",
      "additional_data": { "blocklisted_session_id": null, "blocklisted_session_number": null, "api_service": null },
      "log_type": "error",
      "short_description": "Phone number in blocklist",
      "long_description": "The system detected that the phone number is in the blocklist, which is not allowed.",
      "node_id": "feature_phone_1"
    },
    {
      "feature": "PHONE",
      "risk": "VOIP_NUMBER_DETECTED",
      "additional_data": null,
      "log_type": "information",
      "short_description": "VoIP number detected",
      "long_description": "The system detected that the phone number is a VoIP number, which is not allowed.",
      "node_id": "feature_phone_1"
    }
  ],
  "lifecycle": [
    {
      "type": "PHONE_VERIFICATION_MESSAGE_SENT",
      "timestamp": "2025-08-24T09:11:00.000000Z",
      "details": { "status": "Success", "reason": null, "channel": "sms", "actual_channel": "sms" },
      "fee": 0.0509
    },
    {
      "type": "VALID_CODE_ENTERED",
      "timestamp": "2025-08-24T09:11:10.221340Z",
      "details": { "code_tried": "482917", "status": "Approved" },
      "fee": 0
    },
    {
      "type": "PHONE_VERIFICATION_DECLINED",
      "timestamp": "2025-08-24T09:11:10.350000Z",
      "details": { "reason": "PHONE_NUMBER_IN_BLOCKLIST" },
      "fee": 0
    }
  ],
  "matches": [
    {
      "session_id": null,
      "session_number": null,
      "vendor_data": null,
      "verification_date": null,
      "phone_number": "+15551234567",
      "status": null,
      "is_blocklisted": true,
      "api_service": null,
      "source": "list_entry"
    }
  ],
  "node_id": "feature_phone_1"
}
```

## 관련 항목

* [전화번호 인증 개요](https://docs.didit.me/ko/core-technology/phone-verification/overview.md) — 기능 동작, 요금, 지원되는 채널.
* [전화번호 인증 경고](https://docs.didit.me/ko/core-technology/phone-verification/warnings-phone-verification.md) — 모든 위험 코드, 거부 트리거 및 구성 가능한 작업.
* [데이터 모델 — 전화번호 인증](https://docs.didit.me/ko/reference/data-models.md#전화번호-인증) — 표준 필드별 스키마.
* [독립형 전화번호 API](https://docs.didit.me/ko/standalone-apis/phone-send.md) — `POST /v3/phone/send/` 및 [`POST /v3/phone/check/`](https://docs.didit.me/ko/standalone-apis/phone-check) endpoint.
* [Management API — 목록](https://docs.didit.me/ko/management-api/lists/overview.md) — `source: list_entry`로 `matches[]`에 제공되는 전화번호 차단 목록을 관리합니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.