跳到主要内容
ShieldID

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,您只需链接到它们即可。

/v1 下的 JSON 端点。
EndpointAuthWhat it does
POST /v1/sessionsX-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}/resultX-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 国家代码查询各国家定价。
供您链接的页面,而非需要解析的 JSON。
/v/{session_id}托管验证页面——即会话返回的 verification_url。桌面端会显示二维码;扫描后,申请人的手机会打开同一链接,用于拍摄证件和自拍照。
/c/{session_id}针对某个已验证会话的公开、无需认证的凭证检查页面。注意:目前的响应除了有效/无效标记外,还包含已验证人员的姓名以及证件类型/国家——请勿将此链接交给您不希望其看到这些信息的第三方。
/docs针对您账户 API 源的实时交互式 OpenAPI 参考文档。

创建会话

POST /v1/sessions,端到端说明。

请求,以及确切的返回内容。

bash
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" }
  }'

POST /v1/sessions — 请求字段。
return_urlstring,必填 — 申请人完成后被送回的地址。必须是 http 或 https。
webhook_urlstring,必填 — 签名结果的送达地址。请参阅下文的 Webhooks。
expected_namestring,必填 — 您期望证件上显示的姓名,用于与证件实际内容交叉核对。
expected_dob / expected_addressstring,可选 — 提供时会与证件进行交叉核对;运行验证并不要求提供。
localestring,可选 — "en" 或 "fr"。设置申请人所见托管页面的语言。
metadataobject,可选 — 您自己的参考数据——申请 ID、租户 ID,或任何您希望在结果和 webhook 中原样返回的内容。

结果

GET /v1/sessions/{id}/result — 响应结构。

webhook 载荷采用相同的结构,因此您几乎无需轮询此端点。

顶层字段。
session_id您创建的 ID。
statusPENDING、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您创建会话时发送的任何内容,原样返回。
json
{
  "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)属于附加功能,仅对启用了该功能的账户显示。

会话生命周期

五种状态,一条路径。

会话会自行向前推进;您无需驱动状态机,只需读取状态即可。

status 取值,按顺序排列。
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 文档。

HTTP 状态码、错误码及其含义。
StatusCodeMeaning
401UNAUTHORIZED缺少 X-Api-Key 请求头。
401INVALID_KEY_FORMAT该密钥不是以 vk_sand_ 或 vk_live_ 开头,或与账户下的任何密钥都不匹配。
403FORBIDDEN密钥有效,但无权访问您请求的会话或资源。
404NOT_FOUND不存在具有该 id 的会话、凭证或资源。
409CONFLICT会话所处的状态不允许执行该操作——例如,取消一个已经是 VERIFIED 的会话。
422VALIDATION_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 同步更新的,而不是反过来。

验证签名

javascript
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

保持同步

本参考文档会有变动。请关注更新日志。

字段新增、新错误码和端点变更会先在那里公布,然后才会更新到此处。

常见问题

参考文档常见问题。

下一步

让这份参考文档派上用场。

按照快速入门,依次完成从 sandbox 密钥到已验证会话,再到签名 webhook 的全过程。