Skip to content

Webhooks API

当你的凭证发生某些事件时——被颁发、送达、撤销或查看——Webhooks 会实时通知你的应用。你无需轮询 API,而是注册一个 HTTPS 端点,badges.ninja 会为你订阅的每个事件向它发送一个已签名的 POST

所有管理端点都需要通过 X-Api-Key 请求头进行认证。参见 认证。创建或删除端点需要具有 write 范围的密钥;列出端点需要 read。参见 API 密钥

注册端点

POST /webhooks

参数

参数类型必填说明
urlstring你的 HTTPS 端点。必须以 https:// 开头。
eventsstring[]要订阅的事件类型。省略或传入 ["*"] 可接收所有事件。

示例

bash
curl -X POST https://api.badges.ninja/webhooks \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/badges",
    "events": ["credential.issued", "credential.delivered"]
  }'

响应

201 Created签名密钥只会返回一次——请立即保存;之后无法再次获取。

json
{
  "id": "e4b19ff5-063d-4799-bd75-d03641be624f",
  "url": "https://example.com/hooks/badges",
  "events": ["credential.issued", "credential.delivered"],
  "secret": "2be6d335682c1658242fde3a523fd8a2493bab8c"
}

列出端点

GET /webhooks

返回你已注册的端点。签名密钥永远不会包含在内。

json
{
  "webhooks": [
    {
      "id": "e4b19ff5-063d-4799-bd75-d03641be624f",
      "url": "https://example.com/hooks/badges",
      "events": ["credential.issued", "credential.delivered"],
      "active": true,
      "failureCount": 0,
      "createdAt": 1787685415083,
      "lastStatus": 200,
      "lastDeliveryAt": 1787685480777
    }
  ]
}

删除端点

DELETE /webhooks/{id}
bash
curl -X DELETE https://api.badges.ninja/webhooks/e4b19ff5-063d-4799-bd75-d03641be624f \
  -H "X-Api-Key: bws_your_api_key_here"

发送到该端点的投递会立即停止。

事件类型

事件触发时机……
credential.issued向接收者颁发凭证时。
credential.delivered凭证的通知邮件发送给接收者时(单个或批量)。
credential.revoked凭证被撤销时。
credential.viewed接收者的公开凭证页面被 首次 查看时。

投递载荷

每次投递都是一个 POST,其 JSON 主体具有如下结构:

json
{
  "id": "b1c2d3e4-...",
  "type": "credential.issued",
  "createdAt": 1787685415083,
  "data": { }
}
字段说明
id唯一的投递 id(用它进行去重)。
type事件类型。
createdAt事件时间戳(自纪元起的毫秒数)。
data特定于事件的载荷(见下文)。

按事件类型划分的 data

credential.issued

json
{
  "awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
  "badgeId": "https://api.badges.ninja/certify-badge/badge/<guid>",
  "badgeName": "Advanced Certification",
  "recipient": { "email": "jane@example.com", "name": "Jane Doe" },
  "issuedOn": "2026-08-25",
  "expires": null
}

credential.delivered

json
{
  "awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
  "recipient": { "email": "jane@example.com", "name": "Jane Doe" },
  "badgeName": "Advanced Certification"
}

credential.revoked

json
{ "awardId": "https://api.badges.ninja/certify-badge/award/<guid>", "reason": "Issued in error" }

credential.viewed

json
{
  "awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
  "recipient": { "email": "jane@example.com", "name": "Jane Doe" }
}

请求头

每次投递都会携带这些请求头:

请求头说明
X-Bws-Event事件类型(与主体中的 type 相同)。
X-Bws-Delivery投递 id(与主体中的 id 相同)。
X-Bws-Signaturesha256= 后跟原始请求主体的 HMAC-SHA256,以你的端点密钥为密钥。
User-Agentbadges.ninja-webhooks/1

验证签名

在信任一次投递之前,请务必验证签名。使用你端点的签名密钥计算 原始请求主体 的 HMAC-SHA256,并将其(以恒定时间)与 X-Bws-Signature 请求头进行比较。

js
import crypto from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
  const a = Buffer.from(signatureHeader);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

请使用你收到的确切字节——先解析再重新序列化 JSON 会改变字节并破坏签名。

重试与可靠性

  • 当你的端点以 2xx 状态响应时,投递被视为成功。
  • 失败的投递会重试少数几次。持续失败的端点会累积 failureCount;在 20 次连续失败后,端点会被 自动禁用(active: false)并停止接收投递,直到你修复它并注册一个新端点。
  • 投递可能到达不止一次。使用 X-Bws-Delivery id(或主体中的 id)使你的处理程序具有幂等性。
  • 快速响应(在约 10 秒内)。在确认之后再异步执行繁重工作。

在仪表板中管理 Webhooks

你也可以不使用 API 来管理端点——在仪表板侧边栏打开 Webhooks,即可添加、列出和删除端点,并选择每个端点接收哪些事件。

badges.ninja Documentation