跳转到内容

Webhook

对于您订阅的每个信封事件,Bona Fide 都会向您的端点发送一个 HTTPS POST 请求。投递遵循 Standard Webhooks 规范,因此可以用该规范的任意一个库来验证。

在 设置 › Webhook 中注册,或使用具有 org:manage 权限范围的 API 密钥注册:

Terminal window
curl https://api.bonafidesign.com/v1/webhook-endpoints \
-H "Authorization: Bearer $BONA_FIDE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/hooks/bona-fide",
"description": "Production",
"events": ["envelope.completed", "envelope.sealed", "envelope.declined"]
}'

响应中包含 secret(whsec_…),仅此一次。events 列表为空表示订阅所有事件。URL 必须是公网可访问的 https:// 地址。端点只属于一种模式:使用测试密钥创建的端点只接收测试模式信封的事件,正式端点只接收正式事件。

PATCH /v1/webhook-endpoints/{id} 可更改 URL、事件或描述,也可暂停或恢复端点(enabled)。POST /v1/webhook-endpoints/{id}/test 会发送一个 webhook.test 测试请求。

类型 触发时机
envelope.created 信封已创建
envelope.ready 文档已渲染,信封已准备好交给收件人
recipient.sent 轮到某位收件人(如果是电子邮件投递,其链接已发送)
recipient.viewed 某位收件人首次打开签署页面
recipient.signed 某位收件人已提交(或已被自动会签)
recipient.declined 某位收件人拒绝签署
envelope.completed 所有收件人均已完成。data.values 包含变量和所有填写的值
envelope.sealed 已封存的 PDF 可供下载
envelope.declined 由于有收件人拒绝签署,信封已终止
envelope.voided 您已作废该信封
envelope.expired 在完成之前已超过 expiresAt
signing_link.used 有访问者通过常设签署链接发起了信封

acceptance.created 已在架构中预留,但目前尚不会发出。

{
"id": "evt_9sKq2Lm4Tz",
"type": "envelope.completed",
"createdAt": "2026-10-13T14:09:52.004Z",
"testMode": false,
"data": {
"envelope": {
"id": "env_8Gm2kQ4rT1",
"status": "completed",
"seal": "pending",
"recipients": [{ "id": "rcp_5Jw0pLs9Xe", "role": "client", "status": "completed", "…": "…" }],
"externalId": "user_8841",
"metadata": {},
"…": "…"
},
"values": {
"variables": { "client": { "name": "Acme Robotics, Inc." }, "effective_date": "2026-10-13" },
"recipients": {
"client": { "client_title": "CEO", "start_date": "2026-11-01" }
}
}
}
}

data.envelope 是事件发生时完整的信封。data.values 仅出现在 envelope.completed 中:包括您发送的变量,以及按字段 ID 列出的每个角色的字段值。

每次投递都带有:

请求头 值
webhook-id 事件 ID(evt_…);每次重试都相同。可用于去重
webhook-timestamp 本次尝试签名时的 Unix 时间(秒)
webhook-signature v1,<base64 HMAC-SHA256>,当有多个密钥签名时以空格分隔
user-agent BonaFide-Webhooks/1

签名是对 {webhook-id}.{webhook-timestamp}.{raw body} 计算的 HMAC-SHA256,其密钥为密钥字符串中 whsec_ 之后部分经 base64 解码的结果。请验证原始请求体(在 JSON 解析之前),使用恒定时间比较,并拒绝与您的时钟相差超过五分钟的时间戳。

import express from 'express';
import { Webhook } from 'standardwebhooks'; // npm i standardwebhooks
const wh = new Webhook(process.env.BONA_FIDE_WEBHOOK_SECRET!); // whsec_…
const app = express();
app.post('/hooks/bona-fide', express.raw({ type: 'application/json' }), (req, res) => {
let event;
try {
event = wh.verify(req.body, req.headers as Record<string, string>); // throws if forged or too old
} catch {
return res.sendStatus(400);
}
queue.add(event); // do the work asynchronously and answer quickly
res.sendStatus(204);
});

在 10 秒内返回任意 2xx 即视为投递成功。不会跟随重定向。其他任何情况都会按退避策略重试,分别在 5 秒、5 分钟、30 分钟、2 小时、5 小时、10 小时、14 小时、20 小时和 24 小时后进行,最长持续至事件发生后三天。之后,该投递会被标记为失败。

  • 快速响应并异步处理;根据 webhook-id 去重。
  • 投递可能乱序到达:请检查 data.envelope.status,而不要假定事件的先后顺序。
  • GET /v1/webhook-endpoints/{id}/deliveries 列出最近的投递尝试及其状态码、错误和耗时,每个端点还会显示其 24 小时成功率(health)。
  • POST /v1/events/{id}/redeliver 会将某个事件重新发送到端点,例如在服务中断之后。

POST /v1/webhook-endpoints/{id}/secret/rotate 会立即返回一个新密钥。在接下来的 24 小时内,每次投递都会同时使用新密钥和旧密钥签名(webhook-signature 中有两个条目),这样您就可以在不丢失事件的情况下部署新密钥。