> ## 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.

# 数字身份钱包验证 API

> 通过 Didit，您可以在自己的应用中直接调用数字身份钱包完成身份验证，无需创建验证工作流。

使用专用的钱包 endpoint，从您自己的应用中验证用户。
您无需创建或发布工作流，也无需提供 `workflow_id`。
您的后端发起验证并获取结果；您的界面引导用户完成钱包要求的认证。

> [!NOTE]
>
> API 集成仍需要用户进行认证并授权共享其身份信息。
> 如果没有这一交互，您无法通过提交用户的个人标识符来完成验证。

## 验证流程

1. 您的后端查询[钱包目录](https://docs.didit.me/zh/standalone-apis/digital-id-wallet-catalog.md)，然后使用您的应用 API 密钥调用可用钱包的启动 endpoint。
2. Didit 返回一个验证参考编号，以及用户需要执行的操作。
3. 您的应用打开认证页面或显示钱包的授权说明。
4. 用户通过其钱包完成认证。
5. 您的后端获取已验证的结果，并处理完成通知。

钱包认证是异步的。
启动请求成功仅表示认证已开始，并不表示身份已通过验证。
在将用户视为已验证之前，请务必检查最终结果。

## 后端集成

使用[列出数字 ID 钱包](https://docs.didit.me/zh/standalone-apis/digital-id-wallet-catalog.md)获取您的应用当前可用的 endpoint、必填字段和可用性信息。

请将 `x-api-key` 保存在后端。
不要将其放入浏览器代码包或移动应用中。
为每次新的验证尝试使用不同的 `Idempotency-Key`，重试同一启动请求时复用该密钥。
在复用同一密钥的同时更改请求内容属于冲突，而不是新的验证尝试。

每个钱包都有自己的启动 URL，例如 Finnish Trust Network 的 `/v3/id-verification/wallets/ftn/`。
`request_id` 用于标识该独立验证，供后续操作使用。
使用 `vendor_data` 存放您自己的参考信息，最多 2,000 个 UTF-8 字节；`metadata` 为可选的 JSON 对象。
两者都会随结果和完成 Webhook 一并返回。

| 操作 | endpoint |
| - | - |
| 读取状态和结果 | `GET /v3/id-verification/wallets/verifications/{request_id}/` |
| 轮询手机审批状态 | `POST /v3/id-verification/wallets/verifications/{request_id}/poll/` |
| 提交 Digital Credentials 钱包的响应 | `POST /v3/id-verification/wallets/verifications/{request_id}/response/` |
| 取消待处理的验证 | `POST /v3/id-verification/wallets/verifications/{request_id}/cancel/` |

这些操作使用发起该验证的应用的 API 密钥。
轮询和认证的可用性取决于所选钱包。

取消操作会拒绝待处理的验证且不收费；对于已完成的验证，则原样返回，不作任何更改。
对于 Smart-ID 和 Mobile-ID，如果取消请求到达时轮询正在检查审批状态，系统会等待几秒钟，让该轮询先完成。
随后，如果用户尚未批准，系统将拒绝该验证；如果用户已批准，则将其返回为 `verified`。
如果用户此时正在完成某项验证，则该验证无法取消：响应为 `409`，并带有 `error: "verification_in_progress"` 和 `Retry-After` 响应头。
请等待指定的秒数后重试，以读取已完成的结果。

## 注册返回目标

重定向钱包在认证完成后会将用户带回您的应用。
在启动验证之前，请注册精确的主机名：

```bash theme={null}
curl --request PATCH \
  --url https://verification.didit.me/v3/webhook/ \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{"allowed_return_hosts": ["app.example.com"]}'
```

然后在启动请求中发送 HTTPS 格式的 `return_url`，例如 `https://app.example.com/identity/complete`。
在 `allowed_return_hosts` 中请使用裸主机名，不要包含协议、路径或通配符。
您使用的每个子域名都需要单独注册，最多可注册 20 个主机名。
更新 `allowed_return_hosts` 会替换已注册的列表，因此请包含您希望保留的所有主机名。
`GET /v3/webhook/` 返回当前列表；参见 [Webhook 配置](https://docs.didit.me/zh/sessions-api/management-api.md#webhook-配置)。
注册返回目标无需工作流，也无需白标域名。
该目标是浏览器返回页面；请为您的后端单独配置完成 Webhook。

## 示例: Finnish Trust Network

注册返回主机名后，启动一次 Finnish Trust Network 验证：

```bash theme={null}
curl --request POST \
  --url https://verification.didit.me/v3/id-verification/wallets/ftn/ \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Idempotency-Key: your-unique-attempt-key' \
  --header 'Content-Type: application/json' \
  --data '{
    "country": "FIN",
    "return_url": "https://app.example.com/identity/complete",
    "vendor_data": "your-customer-reference"
  }'
```

保存返回的 `request_id`。
当 `wallet_verification.next_action.url` 的 `type` 为 `redirect` 时，将用户的浏览器跳转至该地址。
用户返回后，由您的后端获取结果：

```bash theme={null}
curl --request GET \
  --url https://verification.didit.me/v3/id-verification/wallets/verifications/REQUEST_ID/ \
  --header 'x-api-key: YOUR_API_KEY'
```

检查 `wallet_verification.outcome`：

| 结果 | 含义 |
| - | - |
| `pending` | 认证仍在进行中。 |
| `verified` | 认证已完成，返回的身份信息已通过验证。 |
| `cancelled` | 用户或您的应用取消了该尝试。 |
| `timeout` | 认证时间窗口已过期。 |
| `failed` | 认证或身份校验失败。 |

只有在结果为 `verified` 且进行的是真实身份检查（`simulated` 为 `false`）时，才能使用返回的身份信息。
处于 pending 状态的响应可能包含下一步操作；终态响应没有下一步操作。

## 认证方式

**重定向类钱包**会返回一个认证 URL。
在用户的浏览器中打开该 URL，让其完成钱包的认证流程，然后将用户重定向回您已注册的目标地址。
请从您的后端读取结果，而不要将返回 URL 参数当作身份证明。

**Smart-ID 和 Mobile-ID** 会在用户的手机上显示审批提示。
您的界面需要收集所需的个人标识符；Mobile-ID 还需要关联的手机号码。
显示比对码，并指示用户仅当手机上的代码与之一致时才进行批准。
用户的 PIN 码应输入到钱包或手机提示中，绝不能出现在您的表单或 API 请求中。
请在您的后端按返回的 `poll_interval_seconds` 间隔轮询，以获取提示反馈。
Didit 还会在后台检查待处理的手机审批，因此即使用户关闭了您的页面，完成通知仍可能到达您的 Webhook。

**Google Wallet** 通过 Digital Credentials API 在您自己的页面或应用中发起请求，无需重定向；请参阅 [Digital Credentials 钱包（Google Wallet）](#digital-credentials-钱包（google-wallet）)。

可用的交互方式取决于所选的钱包。
请勿假设每个钱包都支持嵌入式表单、二维码或无需浏览器的认证。

## Digital Credentials 钱包（Google Wallet）

Google Wallet 由您的网页或 Android 应用直接发起请求，使用 W3C Digital Credentials API。
没有重定向，没有 Didit 托管页面，也没有 Didit 二维码。
它可在生产环境和沙盒中使用。
沙盒应用无需注册；每个生产应用都必须先在控制台（身份证件验证步骤、Google Wallet 行，**向 Google 注册**）中注册一次，才能使用 Google Wallet。
请查看[列出数字 ID 钱包](https://docs.didit.me/zh/standalone-apis/digital-id-wallet-catalog.md)，了解您的应用当前可以发起哪些钱包请求。

**1. 从您的来源开始**

您的后端调用 `POST /v3/id-verification/wallets/google-wallet/`，传入用户的 `country`（`USA`、`GBR`、`BRA`、`SGP` 或 `TWN`），以及将向钱包发起请求的 `origin`。
`origin` 是您页面的 HTTPS 来源，例如 `https://app.example.com`，其主机必须是您的[已注册返回主机名](#注册返回目标)之一，或您的白标域名。
对于 Android 应用，它是 `android:apk-key-hash:` 加上您应用签名证书的 base64 SHA-256 值（不带填充字符）。
钱包会拒绝来自任何其他 origin 的请求。
不存在 `return_url`。

```bash theme={null}
curl --request POST \
  --url https://verification.didit.me/v3/id-verification/wallets/google-wallet/ \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Idempotency-Key: your-unique-attempt-key' \
  --header 'Content-Type: application/json' \
  --data '{
    "country": "USA",
    "origin": "https://app.example.com",
    "vendor_data": "your-customer-reference"
  }'
```

**2. 在用户手势中向钱包发起请求**

响应中包含 `wallet_verification.interaction = "digital_credentials"` 和 `next_action.type = "request_digital_credential"`。
在您发起请求时所用的 `origin` 上，通过点击或轻触操作将 `next_action.digital_credentials.request` 传递给浏览器或 Android Credential Manager。
在桌面端，当钱包位于其他设备上时，浏览器会显示其自己的二维码。

**3. 提交钱包返回的内容**

将返回的 `{protocol, data}` 发送到您的后端，再由后端以 `{"response": {...}}` 的形式提交到 `POST /v3/id-verification/wallets/verifications/{request_id}/response/`。
该请求只能提交一次；第二次提交将返回已作出决定的验证结果。

**4. 读取结果**

提交响应即为已作出决定的验证结果。
您也可以使用 `GET /v3/id-verification/wallets/verifications/{request_id}/` 读取结果，或在完成 Webhook 中接收。

在浏览器中，从点击处理函数向钱包发起请求：

```javascript theme={null}
// start = the JSON your backend returned from the start request
const request = start.wallet_verification.next_action.digital_credentials.request;

button.addEventListener("click", async () => {
  try {
    const credential = await navigator.credentials.get({ digital: request });
    // Send {protocol, data} to your backend, which calls POST .../response/ with your API key.
    await fetch("/api/wallet-response", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        request_id: start.request_id,
        response: { protocol: credential.protocol, data: credential.data },
      }),
    });
  } catch (error) {
    // NotAllowedError or AbortError: the person cancelled. NotSupportedError: this browser cannot ask the wallet.
    console.error(error.name);
  }
});
```

仅当浏览器支持该方法时才提供此功能，例如当 `"DigitalCredential" in window` 为真时。
`navigator.credentials.get` 必须在用户手势中运行，因此请在点击处理函数中调用它，而不要在异步步骤之后调用。

在 Android 上，使用 Jetpack Credential Manager（`androidx.credentials` 1.5.0 或更高版本）发起相同的请求：

```kotlin theme={null}
val option = GetDigitalCredentialOption(
    requestJson = JSONObject(request).toString(), // next_action.digital_credentials.request
)
val result = credentialManager.getCredential(activity, GetCredentialRequest(listOf(option)))
val credentialJson = (result.credential as DigitalCredential).credentialJson // {"protocol": ..., "data": {...}}
// Send credentialJson, parsed as JSON, to your backend as the "response" body.
```

需要处理的错误：

| 错误 | 位置 | 含义 |
| - | - | - |
| `origin_invalid` | 开始，`400` | `origin` 不是 HTTPS 来源，也不是 Android 应用来源。 |
| `origin_not_allowed` | 开始，`400` | 该 origin 的主机未在您的应用中注册。请在 `allowed_return_hosts` 中注册它。 |
| `not_a_digital_credentials_wallet` | 提交，`409` | 此验证不接受钱包响应。 |

未通过验证的凭证会返回一个结果为 `failed` 的已作出决定的验证，而不是错误响应。
只有验证所请求的字段才会从钱包中传出，结果包含钱包返回的身份属性。
Google Wallet ID 凭证或美国州移动驾照不会返回肖像。

在沙盒应用中，该流程会以相同的步骤被模拟，并返回 `simulated: true`。
任何提交的响应都会根据 `sandbox_scenario` 决定验证结果，因此您无需真实凭证即可构建完整的浏览器或应用流程。

## 完成 Webhook

使用 [Webhook 集成指南](https://docs.didit.me/zh/integration/webhooks.md) 为 `status.updated` 配置应用 Webhook 目标。
对于此处描述的决策结构，请使用 `webhook_version: "v3"`。
在处理之前，请在您的后端验证 Webhook 签名。
Webhook 的 `session_id` 与钱包 API 返回的 `request_id` 相匹配。
已完成的钱包身份会出现在 Webhook 的 `decision.id_verifications` 数组中，其中包含 `verification_method: "wallet"`。
您也可以使用该标识符获取专用钱包 API 的结果。

请处理通过和拒绝通知，包括已取消和已过期的验证。
请使您的 Webhook 处理程序具有幂等性，因为失败的投递会被重试。
浏览器返回并不等同于完成 Webhook，其查询参数也不能作为身份证明。

## 返回的身份信息

如果返回这些字段，请使用姓名和出生日期的标准化身份字段。
钱包专属属性描述所选钱包共享的身份信息。
可用属性因钱包和国家/地区而异。
通过身份认证并不意味着肖像、地址或其他所有请求的属性都可以获取。

## 在沙盒中测试

处于 Didit 沙盒模式的应用会模拟钱包验证，不会联系钱包提供方，也不会扣除额度。
响应中会通过 `wallet_verification.simulated: true` 标识这些请求。
模拟通过的结果是示例数据，并非经过验证的真实身份。

对于重定向钱包，请访问返回的 URL，以测试回调并返回您的应用。
对于 Smart-ID 或 Mobile-ID，请使用轮询 endpoint 完成模拟通过；系统不会向手机发送任何通知。
要测试失败处理，请在发起请求时将 `sandbox_scenario` 设置为 `wallet_cancelled`、`wallet_timeout` 或 `wallet_provider_error`。
正式环境的应用会拒绝 `sandbox_scenario`。

Didit 沙盒模拟与针对提供方自有测试环境的测试是相互独立的。
模拟成功并不代表已获得正式的提供方访问权限，也不代表生产环境可用。

### ConnectID 提供方沙盒

ConnectID 的提供方沙盒使用测试银行，与 Didit 沙盒模拟相互独立。
当您的集成已配置提供方沙盒访问时，请将所选银行的 `authorisation_server_id` 传入 [ConnectID 启动端点](https://docs.didit.me/zh/api-reference/digital-id-wallets/connectid.md)。
请使用 ConnectID 银行选择器返回的 ID；不要发送银行 URL 或任意发行方。
省略该字段时，系统会选择默认测试银行。
该字段仅适用于 ConnectID，不会改变所请求的身份属性。

初始数据包请求名字、姓氏和出生日期。
请按照返回的 `next_action` 完成身份认证，然后获取或轮询验证结果。
只有状态为已通过的完整结果才能确认验证成功；返回您的应用并不能确认验证成功。
在完成接入和认证之前，ConnectID 在正式环境中仍为 **即将推出**。

## 可用性与定价

endpoint 覆盖范围与正式环境中的钱包启用状态是两回事。
钱包可能已有 API 参考页面，但仍无法用于正式环境的身份认证。
在实施正式环境流程之前，请检查该钱包的国家/地区覆盖范围和生产状态。

有关已公布的费率和可用性，请参阅[数字身份钱包定价](https://docs.didit.me/zh/getting-started/pricing.md#数字身份钱包定价)。
钱包验证与证件采集分开计费。

## 选择集成方式

如果您希望自行掌控周边界面和应用逻辑，请使用这些 API。
如果您希望使用 Didit 托管的验证流程、工作流规则和已配置的备用步骤，请使用 [Sessions API](https://docs.didit.me/zh/sessions-api/create-session.md)。
两种方式都仍需要钱包的身份认证和同意流程。


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