API 参考
身份验证 API 参考。
您可以调用的每个端点、您会看到的每个返回字段,以及收到 webhook 后该如何处理。有关确切的字段类型,请以您自己 API 源站 /docs 上的在线 OpenAPI 文档为准——本页是通俗易懂的版本。
基础 URL 与环境
一个基础 URL,两个环境。
所有请求都发送到同一个主机。您所处的环境完全取决于您发送的 API 密钥。
| 基础 URL(本文档) | https://api.shieldid.ca — illustrative; your production API origin is published together with your API keys. |
|---|---|
| 认证请求头 | X-Api-Key: <your key>,除下文标注的两个公开端点外,每个请求都需要携带。 |
| Sandbox 密钥前缀 | vk_sand_… — 使用此密钥创建的会话会被标记为 environment: "sandbox",且不会计费。 |
| 生产密钥前缀 | vk_live_… — 请求相同,按您的套餐计费。 |
| 内容类型 | 每个请求正文和响应均使用 application/json。 |
端点
完整的 v1 接口。
六个 JSON 端点,外加一个托管页面和一个公开的凭证检查页,后两者并非 JSON,您只需链接到它们即可。
| Endpoint | Auth | What it does |
|---|---|---|
| POST /v1/sessions | X-Api-Key | 创建验证会话。需要提供 return_url 和 webhook_url。返回 session_id、verification_url 以及 status: "PENDING"。 |
| GET /v1/sessions/{id} | X-Api-Key | 单个会话的状态及概要字段:status、confidence、environment。 |
| GET /v1/sessions/{id}/result | X-Api-Key | 会话达到 VERIFIED 或 FAILED 后的完整结果:person、各项检查结论、confidence、verified_until。 |
| DELETE /v1/sessions/{id} | X-Api-Key | 取消仍处于 PENDING 或 IN_PROGRESS 状态的会话。已处于 VERIFIED、FAILED 或 EXPIRED 的会话无法取消。 |
| GET /v1/credentials/{token} | None — public | 检查已验证凭证当前是否有效。无需 API 密钥,因此可从浏览器调用。注意:目前的响应除了有效/无效标记外,还包含已验证人员的姓名以及证件类型/国家——请勿将此链接交给您不希望其看到这些信息的第三方。 |
| GET /v1/pricing/{country} | X-Api-Key | 按两位字母 ISO 3166-1 国家代码查询各国家定价。 |
| /v/{session_id} | 托管验证页面——即会话返回的 verification_url。桌面端会显示二维码;扫描后,申请人的手机会打开同一链接,用于拍摄证件和自拍照。 |
|---|---|
| /c/{session_id} | 针对某个已验证会话的公开、无需认证的凭证检查页面。注意:目前的响应除了有效/无效标记外,还包含已验证人员的姓名以及证件类型/国家——请勿将此链接交给您不希望其看到这些信息的第三方。 |
| /docs | 针对您账户 API 源的实时交互式 OpenAPI 参考文档。 |
创建会话
POST /v1/sessions,端到端说明。
请求,以及确切的返回内容。
curl -X POST https://api.shieldid.ca/v1/sessions \
-H "X-Api-Key: vk_sand_your_key" \
-H "Content-Type: application/json" \
-d '{
"return_url": "https://yourapp.example/verified",
"webhook_url": "https://yourapp.example/hooks/shieldid",
"expected_name": "Jordan Smith",
"locale": "en",
"metadata": { "application_id": "app_9182" }
}'| return_url | string,必填 — 申请人完成后被送回的地址。必须是 http 或 https。 |
|---|---|
| webhook_url | string,必填 — 签名结果的送达地址。请参阅下文的 Webhooks。 |
| expected_name | string,必填 — 您期望证件上显示的姓名,用于与证件实际内容交叉核对。 |
| expected_dob / expected_address | string,可选 — 提供时会与证件进行交叉核对;运行验证并不要求提供。 |
| locale | string,可选 — "en" 或 "fr"。设置申请人所见托管页面的语言。 |
| metadata | object,可选 — 您自己的参考数据——申请 ID、租户 ID,或任何您希望在结果和 webhook 中原样返回的内容。 |
结果
GET /v1/sessions/{id}/result — 响应结构。
webhook 载荷采用相同的结构,因此您几乎无需轮询此端点。
| session_id | 您创建的 ID。 |
|---|---|
| status | PENDING、IN_PROGRESS、VERIFIED、FAILED 或 EXPIRED。 |
| environment | "sandbox" 或 "production",与创建会话所用的密钥一致。 |
| person | 从证件中读取的字段:姓名、出生日期、证件类型、证件所属国家和辖区、地址。 |
| checks | 每项检查对应一个结论——详见下文。绝不是一个不透明的分数。 |
| confidence | 本次验证的单一总体数值。各项检查(包括人脸匹配)仍会依据固定的判定线单独报告——此字段并不取代它们。 |
| verified_until | 在状态为 VERIFIED 的会话中,结果被视为有效的时长。 |
| failure_reason | 在状态为 FAILED 的会话中设置——例如 FACE_MATCH_BELOW_THRESHOLD 或 CANCELLED_BY_API。否则为 null。 |
| metadata | 您创建会话时发送的任何内容,原样返回。 |
{
"session_id": "ses_9f2c1a",
"status": "VERIFIED",
"environment": "sandbox",
"person": {
"name": "Jordan Smith",
"dob": "1994-03-11",
"document_type": "drivers_licence",
"document_country": "CA",
"document_jurisdiction": "ON"
},
"checks": {
"document": "PASS",
"liveness": "PASS",
"antispoof": "PASS",
"face_match": "PASS"
},
"confidence": 88,
"verified_until": "2027-03-11T00:00:00Z",
"failure_reason": null,
"metadata": { "application_id": "app_9182" }
}Add-onchecks.document、checks.liveness、checks.antispoof 和 checks.face_match 的结果分别为 PASS、FAIL 或 SKIPPED。名单筛查(checks.sanctions——CLEAR、MATCH 或 SKIPPED)属于附加功能,仅对启用了该功能的账户显示。
会话生命周期
五种状态,一条路径。
会话会自行向前推进;您无需驱动状态机,只需读取状态即可。
| PENDING | 已创建。尚无人打开 verification_url。 |
|---|---|
| IN_PROGRESS | 申请人已打开链接,正处于采集流程中的某个环节。 |
| VERIFIED | 所有检查均已运行,结果已就绪。终态——请调用结果端点或读取 webhook。 |
| FAILED | 至少有一项检查未通过。failure_reason 会说明原因。即将推出:可将会话重置为 PENDING 的重试功能——在此之前,请将 FAILED 视为终态,如果申请人想再试一次,请创建新的会话。 |
| EXPIRED | 无人在规定时间内完成。会话在默认时间窗口(30 分钟)后自动过期;请创建新的会话重试。 |
DELETE /v1/sessions/{id} 可提前取消处于 PENDING 或 IN_PROGRESS 状态的会话。已达到 VERIFIED、FAILED 或 EXPIRED 的会话无法取消——它已经结束了。
错误
需要提前规划的内容。
这是目前值得针对性编码的精简清单。完整且最新的错误码和响应内容请参见 /docs 上的在线 OpenAPI 文档。
| Status | Code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | 缺少 X-Api-Key 请求头。 |
| 401 | INVALID_KEY_FORMAT | 该密钥不是以 vk_sand_ 或 vk_live_ 开头,或与账户下的任何密钥都不匹配。 |
| 403 | FORBIDDEN | 密钥有效,但无权访问您请求的会话或资源。 |
| 404 | NOT_FOUND | 不存在具有该 id 的会话、凭证或资源。 |
| 409 | CONFLICT | 会话所处的状态不允许执行该操作——例如,取消一个已经是 VERIFIED 的会话。 |
| 422 | VALIDATION_ERROR | 缺少必填字段或字段格式有误——例如 return_url 不是有效的 http 或 https URL。 |
Webhook
签名、投递、重试。
当会话达到 VERIFIED 或 FAILED 状态时,ShieldID 会将上文所述的数据结构以 POST 方式发送到您的 webhook_url。
- 以 POST 方式投递,JSON 请求体与上述结果结构一致。
- 使用 HMAC-SHA256 对原始请求体签名,并通过 X-Bio-Signature 请求头发送。在信任载荷之前,请先用您的 webhook 密钥进行验证。
- 如果您的端点没有返回 2xx 状态码,最多会以线性退避方式重试三次。
- 即将推出:FAILED 会话的重试功能,在其得出结果后会再投递一次 webhook。目前请遵循每个会话一个 webhook 的规则。
- 此处的字段名称与本参考文档一致。如果实际收到的内容有所不同,请以在线载荷为准并告知我们——字段列表是随 API 同步更新的,而不是反过来。
验证签名
import crypto from "node:crypto";
function isValidShieldIdSignature(rawBody, signatureHeader, secret) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const provided = signatureHeader || "";
const a = Buffer.from(expected, "hex");
const b = Buffer.from(provided, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// rawBody must be the exact, unparsed request body
app.post("/hooks/shieldid", express.raw({ type: "application/json" }), (req, res) => {
const ok = isValidShieldIdSignature(req.body, req.headers["x-bio-signature"], process.env.SHIELDID_WEBHOOK_SECRET);
if (!ok) return res.status(401).send("invalid signature");
const result = JSON.parse(req.body);
// result.session_id, result.status, result.checks, …
res.status(200).send("ok");
});幂等性与重试
构建可安全重复执行的处理程序。
目前在创建会话或投递 webhook 时,还没有专用的幂等键。
- 同一会话的 webhook 重试投递可能会多次到达。请以 session_id + status 作为处理程序的键,并确保写入结果的操作具有幂等性。
- 超时后不要盲目重试 POST /v1/sessions——请先检查会话是否已创建,否则一个申请人可能最终产生两个会话。
- 计划为创建会话提供专用的 Idempotency-Key 请求头。
即将推出创建会话时支持 Idempotency-Key
常见问题