Webhooks API
打印任务完成或失败时主动推送通知,不必轮询任务状态。包含端点管理、事件结构、签名校验与重试机制。
Webhooks API
轮询 GET /v1/print-jobs/{id} 也能知道结果,但总要等下一次轮询。Webhook 是即时的:任务进入终态的那一刻,PrintBase 会把一个带签名的 JSON 事件 POST 到你的地址。
Webhook 是付费套餐功能。免费套餐创建或修改端点会返回 403 PLAN_LIMIT_EXCEEDED。
事件类型
| 事件 | 触发时机 |
|---|---|
print_job.completed | 代理端报告任务打印成功 |
print_job.failed | 任务进入终态失败,具体原因见 reason_code |
端点只会收到自己 events 数组里列出的事件。保存时无法识别的事件名会被直接丢弃,所以建议对照返回体确认实际存下来的是什么。
创建端点
POST /v1/webhooks,需要 api_keys:write 权限。
curl https://api.printbase.cloud/v1/webhooks \
-H "Authorization: Bearer pb_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "发货服务",
"url": "https://example.com/hooks/printbase",
"events": ["print_job.completed", "print_job.failed"]
}'返回:
{
"id": "wh_abc",
"organization_id": "org_abc",
"name": "发货服务",
"url": "https://example.com/hooks/printbase",
"secret": "whsec_...",
"events": ["print_job.completed", "print_job.failed"],
"status": "active",
"created_at": "2026-08-22T09:11:04Z",
"updated_at": "2026-08-22T09:11:04Z"
}字段说明:
name和url必填。URL 必须是公网可达的 HTTP/HTTPS 地址,内网与回环地址会被INVALID_REQUEST拒绝——避免端点被指向内部基础设施。secret可选。不传则由 PrintBase 生成一个whsec_...,在本次返回和后续GET中都能读到。status取active或disabled,默认active。禁用的端点收不到任何事件,也无法测试。
端点管理
| 方法 | 路径 | 权限 | 作用 |
|---|---|---|---|
GET | /v1/webhooks | api_keys:read | 列出所有端点 |
GET | /v1/webhooks/{id} | api_keys:read | 读取单个端点(含 secret) |
PATCH | /v1/webhooks/{id} | api_keys:write | 修改 name、url、secret、events、status |
DELETE | /v1/webhooks/{id} | api_keys:write | 删除端点 |
POST | /v1/webhooks/{id}/test | api_keys:write | 发送一条示例 print_job.completed 事件 |
GET | /v1/webhooks/{id}/deliveries | api_keys:read | 查看最近的投递记录 |
PATCH 只更新你传的字段,未传的保持原值;传了 events 则整体替换原列表。
事件结构
每次投递都是一个 POST,body 结构统一:
{
"id": "evt_abc",
"type": "print_job.failed",
"created_at": "2026-08-22T09:12:41Z",
"organization_id": "org_abc",
"data": {
"job_id": "job_abc",
"printer_id": "printer_123",
"printer_name": "仓库斑马机",
"computer_id": "cmp_456",
"computer_name": "wh-pc-02",
"status": "failed",
"reason_code": "PRINTER_OFFLINE",
"message": "printer is offline",
"created_at": "2026-08-22T09:12:30Z",
"last_updated_at": "2026-08-22T09:12:41Z"
}
}data.status 为 completed 或 failed。失败时 data.reason_code 取值为
AGENT_OFFLINE、PRINTER_OFFLINE、DOWNLOAD_FAILED、PRINT_ERROR、
INVALID_CONTENT 之一,各自含义见 Print Jobs API。
每个请求都带这些头:
| 请求头 | 值 |
|---|---|
X-PrintBase-Event | 事件类型,如 print_job.completed |
X-PrintBase-Event-Id | 事件 ID,如 evt_abc,用于去重 |
X-PrintBase-Signature | t=<unix 秒>,v1=<hex hmac> |
校验签名
签名是以端点 secret 为密钥、对 "{timestamp}.{原始 body}" 做的 HMAC-SHA256。必须用原始请求体校验——先解析成对象再序列化回去,字节就变了,签名一定对不上。
import crypto from 'node:crypto';
export function verify(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(
header.split(',').map((kv) => kv.split('=').map((s) => s.trim()))
);
const { t, v1 } = parts;
if (!t || !v1) return false;
// 拒绝重放很久以前那条合法签名
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(v1, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Express 里要先把原始 body 留住:
app.post(
'/hooks/printbase',
express.raw({ type: 'application/json' }),
(req, res) => {
const raw = req.body.toString('utf8');
if (!verify(raw, req.get('X-PrintBase-Signature'), process.env.PRINTBASE_WEBHOOK_SECRET)) {
return res.sendStatus(400);
}
res.sendStatus(200); // 先应答
handleEvent(JSON.parse(raw)); // 再做耗时的事
}
);重试与投递记录
返回任意 2xx 视为投递成功。其他情况——非 2xx、超时、连接失败——会重试两次,分别在 5 秒和 30 秒后。第三次仍失败则标记为 failed,不再重试。请求超时是 5 秒,所以务必先应答、再异步处理。
由于重试可能发生在你其实已经处理过的那次请求之后(比如一个超时之后才返回的 200),处理函数必须幂等,按 X-PrintBase-Event-Id 去重。
用投递记录接口查具体发生了什么:
curl "https://api.printbase.cloud/v1/webhooks/wh_abc/deliveries?limit=20" \
-H "Authorization: Bearer pb_live_xxx"[
{
"id": "whd_abc",
"endpoint_id": "wh_abc",
"event_id": "evt_abc",
"event_type": "print_job.failed",
"job_id": "job_abc",
"status": "retrying",
"attempts": 1,
"last_http_status": 502,
"last_error": "non-2xx response",
"next_retry_at": "2026-08-22T09:12:46Z",
"created_at": "2026-08-22T09:12:41Z",
"updated_at": "2026-08-22T09:12:41Z"
}
]status 取值为 pending、retrying、success、failed。limit 默认 50,最大 200。
测试端点
POST /v1/webhooks/{id}/test 会发送一条示例 print_job.completed 事件,job_id 为 job_test,签名方式与真实事件完全一致——不用真的打一张纸就能验证你的校验代码。
curl -X POST https://api.printbase.cloud/v1/webhooks/wh_abc/test \
-H "Authorization: Bearer pb_live_xxx"{ "status": "queued", "delivery_id": "whd_xyz" }接口在投递入队后即返回,结果去 /v1/webhooks/{id}/deliveries 查看。