FixWeb

// docs / webhooks

Webhooks

FixWeb 会为扫描完成、终端失败、高 severity finding、live monitor alert 和 scheduled run 发送带签名的出站 Webhook。投递是 at-least-once,并会重试约 24 小时。

设置

打开 Account → Webhooks,创建 HTTPS endpoint,并在接收端保存一次性显示的 whsec_ secret。Webhook 适用于付费计划。

  1. Account → Webhooks 创建 endpoint。
  2. 选择 FixWeb 应发送到该 endpoint 的事件。
  3. 立即复制 secret;它只显示一次,之后只能轮换。

事件

上线事件范围覆盖团队通常接入 CI、告警或工单的关键时刻:

  • scan.completed — 扫描转换为 completed 时触发。Payload: scan id、target、mode、severity-bucket counts、report link。
  • scan.failed — 终端失败通知。Payload: scan id、failed phase、error 和 report link。
  • 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>。

json
{
  "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://fixweb.app/dashboard/scans/8f1c4e2a-..."
    }
  }
}

签名

FixWeb 使用 HMAC-SHA-256 签名原始 JSON body。请在解析或信任事件数据前验证签名。Headers:

  • fixweb-signature: t=<timestamp>,v1=<hex hmac>
  • fixweb-event: scan.completed
  • fixweb-delivery: <uuid> (幂等键)
ts
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);
}

重试

任何非 2xx 响应、timeout、DNS failure 或 SSRF safety block 都会用 exponential backoff 重试约 24 小时。投递记录会在 Account → Webhooks 中显示 response status、短 response excerpt、attempt count 和 dead-letter state。

Webhooks — Docs · FixWeb