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

# 发送验证码（OTP）

> 调用 POST /open-api/customer/v1/send-otp，通过 DCS 的短信或邮件通道向用户发送接入机构生成的验证码（OTP）。

调用 `POST /open-api/customer/v1/send-otp`，通过 DCS 的短信或邮件通道向用户发送接入机构生成的验证码（OTP）。
本接口**不生成、不校验** OTP——OTP 的产生与核对都由接入机构负责，DCS 只做投递。

## 📄 正文

无论您已有自己的短信网关，还是希望由 DCS 发送验证码，都可以通过本接口把验证码发送到用户的手机或邮箱。您只需生成 OTP 并提交给 DCS。本接口面向合作伙伴自管模式的接入机构，适用于需要通过短信或邮件向用户发送验证码的业务流程。

<Info>
  本接口**不负责生成或校验 OTP**。OTP 由接入机构自行生成、自行保管、自行核对，DCS 仅按您指定的 `channel` 把 OTP 内容发出。
</Info>

### 整体流程（谁做什么）

| 步骤 | 谁做   | 动作                                       |
| -- | ---- | ---------------------------------------- |
| 1  | 接入机构 | 生成 6 位数字 OTP，并在自有系统中保管，用于后续核对            |
| 2  | 接入机构 | 选定发送渠道（`SMS` 或 `EMAIL`），准备好对应收件人（手机号或邮箱） |
| 3  | 接入机构 | 生成唯一的 `otpSendRef`（业务幂等键），调用本接口          |
| 4  | DCS  | 校验资质与签名，按渠道把 OTP 提交给短信或邮件服务商             |
| 5  | DCS  | 按收件人维度做频次控制，记录发送结果                       |
| 6  | 接入机构 | 根据响应 `data.status` 判断是否提交成功              |

### 接口

**`POST /open-api/customer/v1/send-otp`**

鉴权请求头与其余 `/open-api/` 接口一致，需带 `X-DAPI-API-KEY`、`X-DAPI-TIMESTAMP`、`X-DAPI-NONCE`、`X-DAPI-SIGN`，并设置 `Content-Type: application/json`。详见[鉴权指南](../../integration-resources/authentication)。

#### 请求体字段

| 字段                 | 类型     | 必填   | 约束     | 说明                                                                           |
| ------------------ | ------ | ---- | ------ | ---------------------------------------------------------------------------- |
| `otpSendRef`       | string | 是    | 最大 50  | OTP 发送幂等号，**全局唯一**，重复会被拒                                                     |
| `channel`          | string | 是    | 最大 20  | 发送渠道，枚举 `SMS` / `EMAIL`                                                      |
| `language`         | string | 是    | —      | 验证码信息语言，枚举 `en`（英文）/ `zh`（中文）                                                |
| `encryptionIV`     | string | 条件必填 | 最大 32  | AES-GCM 模式的 IV；**任一加密字段非空时必填**，用于解密下列密文字段                                    |
| `mobileEncryption` | string | 条件必填 | 最大 128 | 手机号密文（AES-GCM）；`channel=SMS` 时与 `mobile` 二选一                                 |
| `mobile`           | string | 条件必填 | 6–30   | 手机号明文；`channel=SMS` 时与 `mobileEncryption` 二选一；带国家前缀须以 `+` 开头，如 `+6591234567` |
| `emailEncryption`  | string | 条件必填 | 最大 256 | 邮箱密文（AES-GCM）；`channel=EMAIL` 时与 `email` 二选一                                 |
| `email`            | string | 条件必填 | 最大 100 | 邮箱明文；`channel=EMAIL` 时与 `emailEncryption` 二选一                                |
| `otpEncryption`    | string | 条件必填 | 最大 64  | OTP 密文（AES-GCM）；与 `otp` 二选一                                                  |
| `otp`              | string | 条件必填 | 长度 6   | OTP 验证码明文，6 位数字；与 `otpEncryption` 二选一                                        |

**按渠道的必填组合：**

| `channel` | 必填字段组合                                                    |
| --------- | --------------------------------------------------------- |
| `SMS`     | （`mobile` 或 `mobileEncryption`）+（`otp` 或 `otpEncryption`） |
| `EMAIL`   | （`email` 或 `emailEncryption`）+（`otp` 或 `otpEncryption`）   |

#### 明文与密文

收件人字段（`mobile` / `email`）与 OTP 内容（`otp`）都支持明文与密文两种传法。这类敏感信息**强烈建议使用密文传输**：

* **密文**：填 `mobileEncryption` / `emailEncryption` / `otpEncryption`，采用 **AES-GCM** 算法，密钥为接入机构的 **SecretKey**，IV 通过 `encryptionIV` 字段传递。只要任一密文字段非空，`encryptionIV` 必填。
* **明文**：填 `mobile` / `email` / `otp`，直接传递。
* 当同一项的明文与密文都提供时，**以密文为准**。

#### 最小请求示例（SMS，明文）

```json theme={null}
{
  "otpSendRef": "otp-20260617-0001",
  "channel": "SMS",
  "language": "zh",
  "mobile": "+6591234567",
  "otp": "123456"
}
```

#### 最小请求示例（EMAIL，密文）

```json theme={null}
{
  "otpSendRef": "otp-20260617-0002",
  "channel": "EMAIL",
  "language": "en",
  "encryptionIV": "<base64-iv>",
  "emailEncryption": "<aes-gcm-ciphertext>",
  "otpEncryption": "<aes-gcm-ciphertext>"
}
```

#### 响应示例

```json theme={null}
{
  "code": "SYS_SUCCESS",
  "message": "success",
  "messageDetail": null,
  "data": {
    "otpSendRef": "otp-20260617-0001",
    "status": "SUCCESS"
  }
}
```

> **统一响应结构**：所有 `/open-api/` 接口返回 `{ code, message, messageDetail, data }`。`code` 为业务码（成功为 `SYS_SUCCESS`），`messageDetail` 在需要面向终端用户展示时携带可读文案（含 `title`/`type`/`action`/`linkUrl` 等），否则可能为空。请以 `code` 判断业务成败，不要仅凭 HTTP 状态码或 `message` 文案判断。

#### 响应字段（`data`）

| 字段           | 类型     | 说明                           |
| ------------ | ------ | ---------------------------- |
| `otpSendRef` | string | 回显本次的发送幂等号                   |
| `status`     | string | 发送状态，枚举 `SUCCESS` / `FAILED` |

> `status=SUCCESS` 仅表示 **DCS 已把 OTP 成功提交给短信或邮件服务商**，并**不保证用户最终一定收到**（可能受运营商或邮箱服务商影响）。`status=FAILED` 时，具体原因以响应 `code` 字段为准。

### 频次限制

为防止短信/邮件被滥用，DCS 对**同一 Enterprise 下同一收件人**的发送做频次控制：

| 维度                        | 限制              |
| ------------------------- | --------------- |
| 同一 (`channel`, recipient) | 60 秒内只能成功发送 1 次 |

超过限制会返回 `OTP_SEND_TOO_FREQUENT`。请引导用户**稍后重试**，而不要立即重发。

### 幂等

`otpSendRef` 是接入机构侧的业务幂等键，**同一 `otpSendRef` 不能重复发送**：

* 首次请求：正常下发并记录该 `otpSendRef`。
* 重复请求（相同 `otpSendRef`）：返回 `OTP_SEND_REF_NOT_UNIQUE`。

请确保每次发送都使用唯一的 `otpSendRef`（推荐用「业务单号 + 时间戳」生成）。

### 常见错误码

| 错误码                       | 含义                | 是否可重试  | 接入机构怎么办                 |
| ------------------------- | ----------------- | ------ | ----------------------- |
| `OTP_SEND_REF_NOT_UNIQUE` | `otpSendRef` 已被用过 | 否（需换号） | 换一个唯一的 `otpSendRef` 后再发 |
| `OTP_SEND_TOO_FREQUENT`   | 同一收件人发送过于频繁       | 是（需退避） | 提示用户稍后再试，到达冷却时间后重发      |
| `ILLEGAL_ARGUMENT_ERROR`  | 参数非法              | 否（需改参） | 检查必填组合、长度与枚举取值          |
| `SYSTEM_ERROR`            | 系统错误              | 是      | 退避后重试；持续失败请联系客户成功团队     |

完整业务码与错误码归类见[授权拒绝与错误码](../transactions/decline-codes)。

### 前置条件

* 已拥有 Enterprise 的 **ApiKey / SecretKey**，并完成签名与白名单配置（参见[前置准备](../../getting-started/first-steps)与[鉴权指南](../../integration-resources/authentication)）。
* 如使用密文传输，您的系统需支持 **AES-GCM** 加密，密钥即 Enterprise 的 SecretKey。

## 下一步

OTP 发送验证通过后，您可以继续完成[创建用户](./create-customer)与后续的 KYC、开卡流程。
