关于 didit-id-document-verification
通过证件图像或 PDF 调用 Didit ID Verification API 的技能,供开发者自动识别证件、提取字段并校验数据,返回审核状态和警告。
主要功能
- 01自动分类证件
- 02提取 OCR、MRZ 和条码信息
- 03交叉校验日期与号码格式
- 04检测重放和图像篡改
- 05返回提取字段与警告
适用场景
- 01核验用户提交的证件图像
- 02为申请流程提取证件信息
- 03在注册前检查证件有效性
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ didit-protocol/ skills --skill didit-id-document-verification安装后在 Claude Code 中输入/didit-id-document-verification确认已加载。
附带文件scripts/verify_id.py
详细介绍
Didit 身份验证 API
概述
通过一次同步调用,使用身份证件正反面的图像(或 PDF)验证身份。自动识别证件类型(无需指定国家或类型),使用 OCR 读取视觉区域,解码 MRZ 和条形码,交叉核验日期、号码格式和 MRZ 校验位,并默认检查两张图像是否存在屏幕重放、打印副本和肖像篡改。返回提取的字段、Approved 或 Declined 状态,以及 warnings 列表。
主要限制:
- 格式:JPEG、PNG、WebP、TIFF 或 PDF(扩展名为
jpg、jpeg、png、webp、tiff、pdf)。加密的 PDF 需要提供front_image_password/back_image_password - 最大上传大小:每面 10 MB(超出会返回
400)。图像会在服务器端压缩 - 请发送未裁剪的完整拍摄图像,并确保四个角都清晰可见;服务会自行检测、对齐并裁剪证件
- 只要证件有背面,就请发送
back_image:许多身份证件的 MRZ 或条形码位于背面;缺少背面图像时,这些字段会留空,且不会返回警告
**覆盖范围:**来自 220 多个国家和地区的 14,000 多种证件类型:护照、国民身份证、驾照、居留许可等。
**价格:**每次返回 200(Approved 或 Declined)的调用收费 $0.20;400 响应不收费,单独调用没有免费额度。此为 2026 年 11 月 1 日前的标价,届时 Didit 将调整价格,每月 500 次免费检查将变为每月 $10 的免费额度。请查看 didit.me/pricing 了解当前价格。数字身份钱包单独计费(参见数字身份钱包(单独服务))。
**沙盒:**沙盒 API 密钥会跳过处理和计费,并在请求验证通过后返回一份静态的 Approved 模拟结果(虚构的美国“Sandbox User”身份证)。不会存储任何数据。
API 参考: https://docs.didit.me/standalone-apis/id-verification
功能指南: https://docs.didit.me/core-technology/id-verification/overview
警告: https://docs.didit.me/core-technology/id-verification/warnings-id-verification
支持的证件: https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification
身份验证
每个请求都需要 x-api-key 标头。使用 Didit Business Console 中 Developers > API keys 下的应用 API 密钥,或以编程方式创建账户和密钥(参见“开始使用”)。具有自定义访问权限的命名密钥需要 Sessions 写入权限才能运行单独检查;仅限某些工作流或仅限已批准会话的密钥无法运行这些检查。
开始使用(尚无账户?)
如果你没有 Didit API 密钥,只需调用 2 次 API 即可创建:
- 注册: 使用
{"email": "[email protected]", "password": "MyStr0ng!Pass"}调用POST https://apx.didit.me/auth/v2/programmatic/register/ - 检查电子邮件,获取 6 位验证码
- 验证: 使用
{"email": "[email protected]", "code": "A3K9F2"}调用POST https://apx.didit.me/auth/v2/programmatic/verify-email/。密钥位于响应中的application.api_key。
添加额度: 使用 GET /v3/billing/balance/ 查询余额;使用 POST /v3/billing/top-up/ 并传入 {"amount_in_dollars": 50},获取 Stripe 结账链接。
如需完整的平台管理功能(工作流、会话、用户、账单),请参阅 didit-verification-management 技能。
端点
POST https://verification.didit.me/v3/id-verification/
标头
| 标头 | 值 | 必填 |
|---|---|---|
x-api-key | 你的 API 密钥 | 是 |
Content-Type | multipart/form-data(由你的 HTTP 客户端设置) | 是 |
请求参数(multipart/form-data)
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
front_image | 文件 | 是 | - | 证件正面。支持 JPEG/PNG/WebP/TIFF/PDF,最大 10 MB |
front_image_password | 字符串 | 否 | - | 加密的 front_image PDF 的密码 |
back_image | 文件 | 否 | - | 证件背面。格式和大小限制相同 |
back_image_password | 字符串 | 否 | - | 加密的 back_image PDF 的密码 |
perform_document_liveness | 布尔值 | 否 | true | 检查两张图片是否为屏幕截图、打印副本或经过人像篡改。检测到任何一项都会拒绝。设为 false 可跳过检查并降低延迟 |
invalid_mrz_action | 字符串 | 否 | DECLINE | 对 MRZ_VALIDATION_FAILED 执行 DECLINE 或 NO_ACTION |
inconsistent_data_action | 字符串 | 否 | DECLINE | 对 DATA_INCONSISTENT 和 MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME 执行 DECLINE 或 NO_ACTION |
expiration_date_not_detected_action | 字符串 | 否 | NO_ACTION | 对 EXPIRATION_DATE_NOT_DETECTED 执行 DECLINE 或 NO_ACTION(许多证件未印有到期日)。检测到已过期的证件时始终会拒绝 |
critical_field_occlusion_action | 字符串 | 否 | DECLINE | 对 CRITICAL_FIELD_OCCLUSION_DETECTED 执行 DECLINE 或 NO_ACTION |
document_or_personal_number_format_mismatch_action | 字符串 | 否 | NO_ACTION | 对 DOCUMENT_NUMBER_FORMAT_MISMATCH 和 PERSONAL_NUMBER_FORMAT_MISMATCH 执行 DECLINE 或 NO_ACTION |
preferred_characters | 字符串 | 否 | latin | latin 或 non_latin:对于同时印有两种文字的证件,指定姓名和地址返回时使用的文字 |
save_api_request | 布尔值 | 否 | true | true:将调用存储为会话(见下文)。false:不存储任何内容 |
vendor_data | 字符串 | 否 | - | 用于标识用户的标识符;会在响应中返回并存储到会话中 |
metadata | JSON 对象 | 否 | - | 以 JSON 编码的字符串字段发送(例如,{"flow":"onboarding"});会在响应中返回并存储到会话中 |
操作字段仅接受 DECLINE 或 NO_ACTION;REVIEW 会返回 400。此端点接受 minimum_age,但不会应用该参数:请根据返回的 date_of_birth / age 执行年龄规则,或使用带有年龄限制的工作流。
save_api_request=true(默认值): 此调用会存储为 API 会话,并显示在 Business Console 中。request_id 是可用于 GET /v3/session/{sessionId}/decision/ 的真实会话 ID,裁剪后的图片会以短时有效的媒体 URL 返回,并会向你的 webhook 目标发送 status.updated webhook。false: 不会存储任何内容,request_id 是一次性 UUID,且 portrait_image、front_image 和 back_image 会以内嵌的 base64 JPEG 字符串返回。
示例
import json
import requests
with open("front.jpg", "rb") as front, open("back.jpg", "rb") as back:
response = requests.post(
"https://verification.didit.me/v3/id-verification/",
headers={"x-api-key": "YOUR_API_KEY"},
files={
"front_image": ("front.jpg", front, "image/jpeg"),
"back_image": ("back.jpg", back, "image/jpeg"),
},
data={
"vendor_data": "user-123",
"perform_document_liveness": "true",
"metadata": json.dumps({"flow": "onboarding"}),
},
timeout=120,
)
if response.status_code != 200:
raise SystemExit(f"{response.status_code}: {response.text}")
id_v = response.json()["id_verification"]
print(id_v["status"], id_v.get("full_name"), [w["risk"] for w in id_v["warnings"]])
const formData = new FormData();
formData.append("front_image", frontImageFile);
formData.append("back_image", backImageFile);
formData.append("vendor_data", "user-123");
formData.append("metadata", JSON.stringify({ flow: "onboarding" }));
const response = await fetch("https://verification.didit.me/v3/id-verification/", {
method: "POST",
headers: { "x-api-key": "YOUR_API_KEY" },
body: formData,
});
const body = await response.json();
console.log(body.id_verification.status, body.id_verification.warnings.map((w) => w.risk));
响应(200 OK)
由于 save_api_request 为 true,此处的图片是媒体 URL。
{
"request_id": "11111111-2222-3333-4444-555555555555",
"id_verification": {
"status": "Approved",
"document_type": "Identity Card",
"document_subtype": "ID_CARD_GENERIC",
"document_number": "YZA123456",
"personal_number": "X9876543L",
"portrait_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-portrait_image.jpg?signature=...",
"front_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-front_image.jpg?signature=...",
"back_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-back_image.jpg?signature=...",
"front_image_camera_front": null,
"back_image_camera_front": null,
"front_image_camera_front_face_match_score": null,
"back_image_camera_front_face_match_score": null,
"front_image_quality_score": {
"focus_score": 78.0,
"brightness_score": 83.2,
"brightness_issue": "ok",
"is_document_fully_visible": true,
"resolution_score": 40.7,
"overall_score": 70.2
},
"back_image_quality_score": null,
"date_of_birth": "1985-03-15",
"age": 41,
"expiration_date": "2030-08-21",
"date_of_issue": "2020-08-21",
"issuing_state": "ESP",
"issuing_state_name": "Spain",
"first_name": "Elena",
"last_name": "Martinez Sanchez",
"full_name": "Elena Martinez Sanchez",
"gender": "F",
"address": "Calle Mayor 10, Madrid",
"formatted_address": "Calle Mayor 10, 28013 Madrid, Spain",
"place_of_birth": "Valencia",
"marital_status": "UNKNOWN",
"nationality": "ESP",
"extra_fields": {"first_surname": "Martinez", "second_surname": "Sanchez"},
"mrz": {
"surname": "MARTINEZ SANCHEZ",
"name": "ELENA",
"country": "ESP",
"nationality": "ESP",
"birth_date": "850315",
"expiry_date": "300821",
"sex": "F",
"document_type": "ID",
"document_number": "YZA123456",
"personal_number": "X9876543L",
"mrz_type": "TD1",
"warnings": [],
"errors": []
},
"parsed_address": {
"street_1": "Calle Mayor 10",
"street_2": null,
"city": "Madrid",
"region": "Comunidad de Madrid",
"postal_code": "28013",
"country": "ES",
"formatted_address": "Calle Mayor 10, 28013 Madrid, Spain",
"is_verified": true
},
"warnings": [],
"barcodes": []
},
"vendor_data": "user-123",
"metadata": {"flow": "onboarding"},
"created_at": "2026-06-12T02:21:56.013573+00:00"
}
被拒绝的结果格式相同,其中 "status": "Declined",拒绝原因位于 warnings 中,例如:
{
"risk": "DOCUMENT_EXPIRED",
"feature": "ID_VERIFICATION",
"additional_data": null,
"log_type": "error",
"short_description": "Document expired",
"long_description": "The document's expiration date has passed, rendering it no longer valid for use."
}
状态值
| 状态 | 含义 |
|---|---|
"Approved" | 没有任何警告导致拒绝 |
"Declined" | 至少一条警告的 log_type: "error"(见 warnings) |
此端点不会返回 In Review。可读取但存在问题的证件仍会返回 HTTP 200 和 Declined:请务必检查 id_verification.status,而不只是 HTTP 状态码。
错误响应
| 代码 | 含义 | 处理方式 |
|---|---|---|
400 | 请求无效 | 阅读响应正文中的字段错误 |
400 | {"error": "COULD_NOT_RECOGNIZE_DOCUMENT"} | 图片中未找到文档:重新拍摄,确保四个角都清晰可见 |
400 | {"detail": "The PDF is encrypted..."} 或 {"detail": "The PDF password is incorrect..."} | 发送 front_image_password / back_image_password,或发送照片 |
400 | {"error": "Failed to convert front image PDF."}(或 back) | 发送图片或有效的 PDF |
401 | API 密钥已过期 | 在 Developers > API keys 中轮换密钥或创建新密钥 |
403 | 缺少、错误或已撤销的 API 密钥;无权访问此端点的范围密钥;来自密钥 IP 允许列表之外的请求;或额度不足 | 查看 detail 或 error 中的消息:修正 x-api-key 标头或密钥的访问权限,或充值 |
429 | 速率限制:每个密钥每分钟最多 300 个 POST/PATCH/DELETE 请求和 600 个 GET 请求 | 等待 Retry-After 指定的秒数,然后重试 |
额度检查会在处理图片前运行:余额为零时会返回 403,并包含 {"error": "You don't have enough credits to perform this request. ..."}。
响应字段参考
除非另有说明,所有字段均位于 id_verification 中。
| 字段 | 类型 | 描述 |
|---|---|---|
request_id(顶层) | uuid | 当 save_api_request=true 时为会话 ID;否则为一次性 UUID |
status | string | "Approved" 或 "Declined" |
document_type | string or null | "Passport"、"Identity Card"、"Driver's License"、"Residence Permit"、"Health Insurance Card"、"Tax Card";无法对证件分类时为 null |
document_subtype | string or null | 更细的子类型,例如 ID_CARD_GENERIC、EPASSPORT |
document_number、personal_number | string or null | 证件号码和次要个人/国家号码 |
first_name、last_name、full_name | string or null | 持证人姓名 |
date_of_birth、expiration_date、date_of_issue | string or null | YYYY-MM-DD |
age | integer or null | 根据 date_of_birth 计算的年龄 |
gender | string or null | "M"、"F" 或 null |
nationality、issuing_state | string or null | ISO 3166-1 alpha-3;issuing_state_name 为国家名称 |
address、formatted_address | string or null | 证件上印制的地址及其地理编码形式 |
parsed_address | object or null | street_1、street_2、city、region、postal_code、country(alpha-2)、formatted_address、is_verified、document_location、label、category |
place_of_birth、marital_status | string or null | 除非证件上有印制,否则 marital_status 为 UNKNOWN |
extra_fields | object or null | 证件特有的附加字段(例如 first_surname、second_surname) |
mrz | object | 解析后的 MRZ:surname、name、country、nationality、birth_date/expiry_date(原始 YYMMDD)、sex、document_type、document_number、personal_number、optional_data、校验位、mrz_type(TD1/TD2/TD3)、mrz_string、errors、warnings。证件没有 MRZ 或无法读取时为 {} |
barcodes | array | 已解码的条码:type(例如 PDF417、QR_CODE)、data、data_raw、side、position |
portrait_image、front_image、back_image | string or null | 媒体 URL(已保存),或 base64 JPEG(save_api_request=false);未上传背面时,back_image 为 null |
front_image_quality_score、back_image_quality_score | object or null | focus_score、brightness_score、brightness_issue、is_document_fully_visible、resolution_score、overall_score(0-100) |
front_image_camera_front、back_image_camera_front 及其 *_face_match_score | null | 此端点始终为 null(仅在托管会话中填充) |
warnings | array | {risk, feature, additional_data, log_type, short_description, long_description};log_type 为 error(拒绝)或 information |
vendor_data、metadata、created_at(顶层) | 回显您提供的值和响应时间戳 |
警告标签
此端点仅支持 DECLINE 或 NO_ACTION:警告的 log_type 为 "error"(状态变为 Declined)或 "information"(仅报告,不影响状态)。
始终拒绝
| 标签 | 描述 |
|---|---|
DOCUMENT_EXPIRED | 过期日期已过 |
SCREEN_CAPTURE_DETECTED | 屏幕照片,而非实体证件(仅在 perform_document_liveness=true 时) |
PRINTED_COPY_DETECTED | 打印件,而非原件(仅在 perform_document_liveness=true 时) |
PORTRAIT_MANIPULATION_DETECTED | 肖像被替换或修改(仅在 perform_document_liveness=true 时) |
PUBLIC_DOCUMENT_IMAGE_DETECTED | 图像与已知的公共互联网证件图像(样本、新闻图片或图库照片)相符 |
NAME_NOT_DETECTED | 无法读取名字和/或姓氏 |
DATE_OF_BIRTH_NOT_DETECTED | 无法读取证件上的出生日期(若证件包含出生日期) |
DOCUMENT_NUMBER_NOT_DETECTED | 无法读取证件号码或个人号码 |
COULD_NOT_DETECT_DOCUMENT_TYPE | 无法从上传内容中读取任何信息;如果也未检测到肖像,则会同时出现 PORTRAIT_IMAGE_NOT_DETECTED |
可按请求配置
| 请求参数(默认值) | 标签 |
|---|---|
invalid_mrz_action(DECLINE) | MRZ_VALIDATION_FAILED(MRZ 校验位或格式验证失败)。缺少 MRZ 不会在此处引发警告 |
inconsistent_data_action(DECLINE) | DATA_INCONSISTENT(正反面信息不一致)、MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME(可视区域信息与 MRZ 不一致) |
critical_field_occlusion_action(DECLINE) | CRITICAL_FIELD_OCCLUSION_DETECTED:身份号码、姓名、出生日期或到期日期被实体遮挡。additional_data.covered_fields 会列出这些字段;通常还会出现相应的 *_NOT_DETECTED 警告 |
expiration_date_not_detected_action(NO_ACTION) | EXPIRATION_DATE_NOT_DETECTED |
document_or_personal_number_format_mismatch_action(NO_ACTION) | DOCUMENT_NUMBER_FORMAT_MISMATCH、PERSONAL_NUMBER_FORMAT_MISMATCH(additional_data 包含 expected_format、extracted_value) |
此端点上的信息提示(从不拒绝)
| 标签 | 描述 |
|---|---|
POSSIBLE_DUPLICATED_USER | 您的应用中有另一份证件具有相同的出生日期、签发国家/地区和非常相似的姓名,但 vendor_data 不同。additional_data.duplicated_session_id |
ID_DOCUMENT_IN_BLOCKLIST | 该证件与您的证件黑名单匹配。此处仅作信息提示(在工作流中会自动拒绝):请检查此项并自行决定 |
ID_DOCUMENT_IN_ALLOWLIST | 该证件号码在您的允许名单中 |
DOCUMENT_SIDES_MISMATCH | 正反面不属于同一份证件 |
UNPARSED_ADDRESS | 该证件包含无法解析或地理定位的地址字段 |
仅限工作流的标签(此处不会产生):DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION、MINIMUM_AGE_NOT_MET、MRZ_NOT_DETECTED、INVALID_DATE、*_MISMATCH_WITH_PROVIDED 系列(需要会话中包含 expected_details)以及前置摄像头自拍标签。
数字身份钱包(独立使用)
通过用户已持有的国家或银行数字身份,在你自己的应用中验证用户身份,无需工作流。用户始终会在钱包中进行身份验证并批准共享信息;仅凭用户的标识符无法验证其身份。端点仅支持 v3。
生产环境中可用的钱包(根据文档;请务必通过目录接口确认,该接口会报告你的应用和环境是否可用):
| 钱包 | 启动端点 | 国家/地区 | 交互方式 | 每次验证通过的登录标价 |
|---|---|---|---|---|
| MitID | POST /v3/id-verification/wallets/mitid/ | DNK | 重定向 | $0.25 |
| BankID Sweden | POST /v3/id-verification/wallets/bankid-se/ | SWE | 重定向 | $0.20 |
| iDIN | POST /v3/id-verification/wallets/idin/ | NLD | 重定向 | $0.85(完整身份识别) |
| Finnish Trust Network | POST /v3/id-verification/wallets/ftn/ | FIN | 重定向 | $0.25 |
| Smart-ID | POST /v3/id-verification/wallets/smart-id/ | EST, LVA, LTU, BEL | 在应用内 | 见定价 |
| Mobile-ID | POST /v3/id-verification/wallets/mobile-id/ | EST, LTU | 在应用内 | 见定价 |
其他钱包虽然有启动端点,但即将推出:它们会以 403 wallet_unavailable 错误拒绝请求。计费方式:每个请求仅在身份验证通过时收费一次;取消、过期或失败的登录均免费,且 500 次免费证件检查不适用。
| 操作 | 端点 |
|---|---|
目录:列出每个钱包的 id、name、path、countries、interaction、required_fields、available | GET /v3/id-verification/wallets/ |
| 启动登录 | POST /v3/id-verification/wallets/<wallet>/(目录中的 path) |
| 读取状态和结果 | GET /v3/id-verification/wallets/verifications/{request_id}/ |
| 请求钱包进行手机批准(Smart-ID、Mobile-ID) | POST /v3/id-verification/wallets/verifications/{request_id}/poll/ |
| 取消待处理的登录(不会收费) | POST /v3/id-verification/wallets/verifications/{request_id}/cancel/ |
启动请求
| 字段 | 钱包 | 必填 | 说明 |
|---|---|---|---|
return_url | 重定向钱包 | 是 | 浏览器返回时使用的 HTTPS URL,后面会附加 request_id 和 result。其主机必须先注册(见下文) |
device | 重定向钱包 | 否 | same_device(默认)或 cross_device(例如用手机扫描二维码) |
country | 全部 | Smart-ID 和 Mobile-ID 必填 | ISO 3166-1 alpha-3 代码;仅支持单一国家/地区的钱包默认使用该国家/地区 |
personal_code | Smart-ID、Mobile-ID | 是 | 用户的国家个人身份识别码(数字和连字符,6 至 20 个字符)。切勿收集 PIN |
phone_number | Mobile-ID | 是 | 在该国家/地区注册了 Mobile-ID 的 E.164 格式号码 |
vendor_data | 全部 | 否 | 你的参考信息,最多 2,000 个 UTF-8 字节 |
metadata | 全部 | 否 | 随结果和 webhook 返回的 JSON 对象 |
sandbox_scenario | 全部 | 否 | 仅适用于沙盒应用:wallet_cancelled、wallet_timeout 或 wallet_provider_error;其他任何值都会验证通过。在线应用不接受此字段 |
请求头 Idempotency-Key(可选,最多 255 个字符):每次尝试使用一个新键,重试时发送同一个键;同一个键搭配不同的钱包或请求体会返回 409 idempotency_key_reused。
只需注册一次返回主机(重定向钱包):发送 PATCH https://verification.didit.me/v3/webhook/,并提供 {"allowed_return_hosts": ["app.example.com"]}。仅限裸主机名(不含协议、路径或通配符),最多 20 个;每次更新都会替换整个列表,可通过 GET /v3/webhook/ 查看。你的白标域名始终允许使用。
响应(启动时为 201,读取、轮询和取消时为 200)
{
"request_id": "00000000-0000-4000-8000-000000000001",
"wallet_verification": {
"wallet": {"id": "ftn", "name": "Finnish Trust Network", "issuing_authority": "Finnish banks and mobile operators (FTN)"},
"country": "FIN",
"status": "Not Finished",
"outcome": "pending",
"error": null,
"interaction": "redirect",
"simulated": false,
"expires_at": "2026-01-01T10:10:00Z",
"next_action": {"type": "redirect", "url": "https://wallet.example.com/authorize"},
"identity": null,
"attributes": null,
"level_of_assurance": null,
"verified_at": null,
"signature_valid": null,
"credential_type": "person_identification"
},
"vendor_data": "user-123",
"metadata": null,
"created_at": "2026-01-01T10:00:00Z"
}
next_action.type:redirect(将浏览器跳转至url)或confirm_in_app(显示verification_code,即钱包应用中显示的 4 位代码;用户在应用中确认;每隔poll_interval_seconds轮询一次)。Didit 也会在后台轮询,因此即使你停止轮询,webhook 也会触发。outcome:pending、verified、cancelled、timeout、failed。status先为Not Finished,之后变为Approved(已验证)或Declined。- 验证通过后会提供
identity:full_name、first_name、last_name、date_of_birth、nationality(仅在钱包声明该信息时提供)、issuing_state。attributes包含钱包自身的声明,因钱包而异。 - 仅当
outcome为verified且simulated为false时,才使用身份信息。 切勿信任return_url上的result查询参数;请从你的后端读取结果。 status.updatedwebhook 携带的session_id与request_id相同;身份信息显示在decision.id_verifications中,其verification_method为"wallet"。
钱包错误
| 代码 | error | 含义 |
|---|---|---|
400 | 字段错误、return_url_invalid、return_url_not_allowed、invalid_personal_code、invalid_phone_number、idempotency_key_invalid | 修正请求;注册 return_url 主机 |
403 | {"detail": ...}、wallet_unavailable、insufficient_credits | 密钥无效、钱包尚未对你开放,或需要充值 |
404 | not_found | 此应用没有对应 request_id 的钱包验证 |
409 | idempotency_key_reused、idempotency_key_in_progress、verification_in_progress(用户正在完成验证时取消) | 使用新密钥,或等待 Retry-After 秒 |
502 | wallet_provider_unavailable | 钱包无法启动;未创建或计费 |
503 | wallet_not_configured | 此环境无法连接到钱包 |
import uuid
import requests
BASE = "https://verification.didit.me/v3/id-verification/wallets"
headers = {"x-api-key": "YOUR_API_KEY"}
catalog = requests.get(f"{BASE}/", headers=headers, timeout=30).json()
live = {w["id"]: w for w in catalog["wallets"] if w["available"]}
if "ftn" in live:
start = requests.post(
f"{BASE}/ftn/",
headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
json={"return_url": "https://app.example.com/identity/complete", "vendor_data": "user-123"},
timeout=30,
).json()
request_id = start["request_id"]
print("Send the browser to:", start["wallet_verification"]["next_action"]["url"])
# After the user returns (or on the webhook), read the result server-side
result = requests.get(f"{BASE}/verifications/{request_id}/", headers=headers, timeout=30).json()
wv = result["wallet_verification"]
if wv["outcome"] == "verified" and not wv["simulated"]:
print("Verified:", wv["identity"]["full_name"], wv["identity"]["date_of_birth"])
API 参考: https://docs.didit.me/standalone-apis/digital-id-wallets
仅限工作流的身份验证方式
这些方式无法通过独立端点使用;请使用工作流和会话(参见 didit-kyc-onboarding 技能):
- NFC 芯片读取: 工作流功能
NFC,放置在OCR之后。在会话期间由原生 iOS/Android SDK 读取芯片;网页浏览器会跳过此步骤。每次成功完成读取收费 $0.15。 - 工作流中的非证件查询和钱包: 在
OCR功能中按国家设置config.methods(证件采集、查询政府登记册或其他权威来源、数字身份钱包,并设置回退规则)。参见 https://docs.didit.me/management-api/workflows/feature-configs 和 https://docs.didit.me/core-technology/id-verification/non-doc-lookup。
常见工作流
基本身份验证
1. POST /v3/id-verification/ -> front_image (+ back_image if the document has a back)
2. If 400 COULD_NOT_RECOGNIZE_DOCUMENT -> ask for a new photo with all corners visible
3. If "Approved" -> use first_name, last_name, date_of_birth, document_number, issuing_state
If "Declined" -> read warnings with log_type "error":
DOCUMENT_EXPIRED -> ask for a valid document
SCREEN_CAPTURE_DETECTED / PRINTED_COPY_DETECTED -> ask for a photo of the physical document
MRZ_VALIDATION_FAILED / NAME_NOT_DETECTED -> ask for a sharper image (and the back side)
4. Check informational warnings too: ID_DOCUMENT_IN_BLOCKLIST, POSSIBLE_DUPLICATED_USER
完整身份验证流程(独立方式)
1. POST /v3/id-verification/ -> verify document, keep portrait_image
2. POST /v3/passive-liveness/ -> verify a real person took the selfie
3. POST /v3/face-match/ -> compare selfie to the document portrait
4. POST /v3/aml/ -> screen the extracted name, date of birth and nationality; convert nationality
from alpha-3 (ESP) to alpha-2 (ES) first, or /v3/aml/ returns 400
5. All Approved -> verified identity
如需使用托管流程为你采集证件和自拍,请使用工作流会话(didit-kyc-onboarding 技能)。
实用脚本
export DIDIT_API_KEY="your_api_key"
python scripts/verify_id.py front.jpg
python scripts/verify_id.py front.jpg back.jpg --vendor-data user-123
python scripts/verify_id.py scan.pdf --front-password secret --no-document-liveness
python scripts/verify_id.py front.jpg back.jpg --preferred-characters non_latin --no-save
python scripts/verify_id.py front.jpg --format-mismatch-action DECLINE --metadata '{"flow": "onboarding"}'