// docs / webhooks
Webhooks
FixVibe 会为扫描完成、终端失败、高 severity finding、live monitor alert 和 scheduled run 发送带签名的出站 Webhook。投递是 at-least-once,并会重试约 24 小时。
设置
打开 Account → Webhooks,创建 HTTPS endpoint,并在接收端保存一次性显示的 whsec_ secret。Webhook 适用于付费计划。
- 从 Account → Webhooks 创建 endpoint。
- 选择 FixVibe 应发送到该 endpoint 的事件。
- 立即复制 secret;它只显示一次,之后只能轮换。
事件
上线事件范围覆盖团队通常接入 CI、告警或工单的关键时刻:
- scan.completed — 扫描转换为 completed 时触发。Payload: scan id、target、mode、severity-bucket counts、report link。
- scan.failed — terminal-failure notification. Payload: scan id, failure reason, and report link when available.
- finding.created — 每个 critical 或 high finding 单独发送。较低 severity 默认并入 scan.completed,以避免事件噪音。
- monitor.alert.fired — Unlimited plan 中,当 certificate transparency logs、DNS records 或 threat-intelligence databases 检测到变化时触发。
- schedule.run.queued — scheduler 将 re-scan 入队时触发。适合 CI orchestration。
Payload 结构
每次投递都使用同一个 envelope: <code>id</code>、<code>type</code>、<code>created_at</code> 和事件专用的 <code>data</code>。
{
"id": "8f1c4e2a-8c3a-4b6f-9c0d-9b1e8f3c2a4d",
"type": "scan.completed",
"created_at": "2026-05-15T10:20:30.000Z",
"data": {
"scan": {
"id": "8f1c4e2a-8c3a-4b6f-9c0d-9b1e8f3c2a4d",
"target_hostname": "staging.example.com",
"mode": "passive",
"status": "completed",
"findings_count": { "critical": 0, "high": 1, "medium": 2, "low": 3, "info": 4 },
"report_url": "https://fixvibe.app/dashboard/scans/8f1c4e2a-..."
}
}
}签名
FixVibe 使用 HMAC-SHA-256 签名原始 JSON body。请在解析或信任事件数据前验证签名。Headers:
fixvibe-signature: t=<timestamp>,v1=<hex hmac>fixvibe-event: scan.completedfixvibe-delivery: <uuid>(幂等键)
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, header: string, secret: string) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const signed = `${parts.t}.${rawBody}`;
const expected = createHmac("sha256", secret).update(signed).digest("hex");
const received = Buffer.from(parts.v1 ?? "", "hex");
const calculated = Buffer.from(expected, "hex");
return received.length === calculated.length && timingSafeEqual(received, calculated);
}重试
Any non-2xx response, timeout, DNS failure, or delivery safety rejection is retried with exponential backoff for about 24 hours. Delivery rows show response status, a short response excerpt, attempt count, and dead-letter state in Account → Webhooks.
