> ## 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，以及跨会话与您的黑名单或其他用户会话的比对结果。

本页说明了决策 endpoint 返回的 JSON 结构，以便您解析每个已验证号码的 OTP 结果、运营商元数据和风险标记。

![Didit 电话验证报告显示了 OTP 结果、运营商元数据和风险标记](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[]` 日志。
* `matches[]` 数组，展示在其他会话（跨 KYC、KYB 及独立 API 验证的任意状态）或您的黑名单中出现的相同号码。
* `warnings[]` 数组：验证过程中触发的风险事件（参见[电话验证警告](https://docs.didit.me/zh/core-technology/phone-verification/warnings-phone-verification.md)）。
* 标识生成该报告的工作流图谱节点的 `node_id`（仅限 V3 会话）。

在托管验证流程中，Didit 会为您处理 OTP 交互。对于直接 API 集成，相同流程分为两次调用：[`POST /v3/phone/send/`](https://docs.didit.me/zh/standalone-apis/phone-send) 用于投递验证码，[`POST /v3/phone/check/`](https://docs.didit.me/zh/standalone-apis/phone-check) 用于核验用户的输入。待验证的 OTP **自首次发送起 5 分钟内有效**（重试不会延长有效期）。在工作流会话中，用户默认拥有 2 次 OTP 发送尝试机会（`phone_max_retries`）和 2 次验证码输入尝试机会（`phone_max_check_attempts`），两者均可针对每个工作流节点进行调整；耗尽任一上限都会使该步骤最终标记为 `Declined`，并返回 `VERIFICATION_CODE_ATTEMPTS_EXCEEDED`。独立电话 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/zh/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`；除非发送被拦截（`invalid_phone_number`、`repeated_attempts`、`suspicious`、`spam`、`unknown`），否则 `reason` 为 `null`；`channel` 为请求的渠道，`actual_channel` 为实际投递的渠道（例如降级为短信的 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 价格加上 $0.02 Didit 费用，如果 WhatsApp 验证码是从[您自己的 WhatsApp Business 号码](https://docs.didit.me/zh/core-technology/phone-verification/overview.md#通过您自己的号码发送-whatsapp-验证码)发送的，则仅收取 $0.02 Didit 费用。在确认投递之前，此价格为预估价格，确认后为实际扣费金额。只有 `Blocked` 发送保证免费：任何其他发送在验证完成或过期时均会计费，即使从未确认投递或消息无法投递也是如此。投递、核验和状态事件始终携带 `fee: 0`。

### 跨会话匹配

`matches[]` 记录了同一应用中出现过相同号码的其他会话 — 涵盖 KYC、KYB 和独立 API 验证，无论其状态如何 — 以及在 [管理 API 列表](https://docs.didit.me/zh/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/zh/core-technology/phone-verification/overview.md) — 功能行为、定价、支持的渠道。
* [电话验证警告](https://docs.didit.me/zh/core-technology/phone-verification/warnings-phone-verification.md) — 所有风险代码、拒绝触发器和可配置操作。
* [数据模型 — 电话验证](https://docs.didit.me/zh/reference/data-models.md#电话验证) — 规范的逐字段架构。
* [独立电话 API](https://docs.didit.me/zh/standalone-apis/phone-send.md) — `POST /v3/phone/send/` 和 [`POST /v3/phone/check/`](https://docs.didit.me/zh/standalone-apis/phone-check) endpoint。
* [管理 API — 列表](https://docs.didit.me/zh/management-api/lists/overview.md) — 管理为 `matches[]`（带有 `source: list_entry`）提供数据的电话黑名单。


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