Webhook
Webhook は、選択したテナントイベントについて署名付きのアウトバウンド POST リクエストを配信するため、ポーリングなしで変更に反応できます。エンドポイントは Settings -> Integrations -> Webhooks またはパブリック API から管理します。
イベント
| イベント | ステータス | 配信 |
|---|---|---|
inventory.item.created | 発行 | 署名付きアウトボックス配信 |
inventory.item.updated | 発行 | 署名付きアウトボックス配信 |
order.created | 発行 | 署名付きアウトボックス配信 |
order.updated | 発行 | 署名付きアウトボックス配信 |
contact.created | 発行 | 署名付きアウトボックス配信 |
contact.updated | 発行 | 署名付きアウトボックス配信 |
stock_document.created | 発行 | 署名付きアウトボックス配信 |
stock_document.updated | 発行 | 署名付きアウトボックス配信 |
user.invited | 発行 | 署名付きアウトボックス配信 |
organization.updated | 発行 | 署名付きアウトボックス配信 |
integration.connected | 発行 | 署名付きアウトボックス配信 |
bom.created | 予定 | コントラクト予約済み、未発行 |
bom.updated | 予定 | コントラクト予約済み、未発行 |
webhook.test | テスト専用 | 署名なしの接続性チェック |
購読する
POST /v1/webhooks(スコープ webhooks:write、Enterprise)でエンドポイントを作成します。署名シークレットはレスポンスで一度だけ返されるため、すぐに保存してください。
curl -X POST https://api.fabhub.app/v1/webhooks \
-H "X-API-Key: $FABHUB_API_KEY" \
-H "Idempotency-Key: 7c1f...-..." \
-H "Content-Type: application/json" \
-d '{"name":"Orders sync","targetUrl":"https://example.com/hooks/fabhub","subscribedEvents":["order.created","order.updated"]}'
{
"data": {
"id": "wh_1",
"name": "Orders sync",
"targetUrl": "https://example.com/hooks/fabhub",
"status": "active",
"environment": "production",
"description": null,
"subscribedEvents": ["order.created", "order.updated"],
"createdAt": "2026-06-20T09:00:00Z",
"updatedAt": "2026-06-20T09:00:00Z"
},
"signingSecret": "whsec_9f3a...stored-once"
}
配信形式
各配信は、JSON イベントボディと以下のヘッダーを含む POST です。
X-FabHub-Event- イベントタイプ(例:order.created)X-FabHub-Timestamp- ペイロードが署名された時刻の unix 秒X-FabHub-Signature-v1=<hex>HMAC。シークレットローテーション中はカンマ区切りの複数のv1=パートが現れます
POST /hooks/fabhub HTTP/1.1
X-FabHub-Event: order.created
X-FabHub-Timestamp: 1718873400
X-FabHub-Signature: v1=4f2c...e1
{ "event": "order.created", "data": { "id": "ord_1", "module": "sell", "status": "open" } }
署名を検証する
署名は HMAC-SHA256(secret, "<timestamp>.<rawBody>") を 16 進エンコードしたもので、secret は 16 進からデコードした署名シークレットです。常に、JSON のパース前に、正確な生のリクエストボディに対して検証してください。 SDK には検証ツールが付属しています。
import { verifyFabHubWebhookSignature } from '@fabhub/sdk';
const result = verifyFabHubWebhookSignature({
signingSecret: process.env.FABHUB_WEBHOOK_SECRET,
rawBody,
timestamp: req.headers['x-fabhub-timestamp'],
signature: req.headers['x-fabhub-signature'],
// toleranceSeconds: 300 (default) - rejects stale/replayed timestamps
});
if (!result.ok) return res.status(400).end();
// safe to JSON.parse(rawBody) now
シークレットローテーション
PATCH /v1/webhooks/{webhook_id} と {"rotateSecret": true} でローテーションします。新しいシークレットは一度だけ返され、オーバーラップウィンドウの間は新旧両方のシークレットで配信が署名されます(signingSecrets 経由で両方を検証ツールに渡してください)。
配信ログ
GET /v1/webhooks/{webhook_id}/deliveries(スコープ webhooks:deliveries:read)で試行を確認します。
{
"data": [
{
"id": "del_1",
"eventType": "order.created",
"status": "delivered",
"attempts": 1,
"lastError": null,
"lastHttpStatus": 200,
"createdAt": "2026-06-20T09:01:00Z",
"updatedAt": "2026-06-20T09:01:01Z"
}
],
"pagination": { "page": 1, "pageSize": 20, "total": 1, "totalPages": 1 }
}
合成テストの ping(webhook.test)は署名なしの接続性チェックであり、アウトボックスログには現れません。
ベストプラクティス
2xxを素早く返し、重い処理は非同期で行ってください。- 配信は少なくとも 1 回(at-least-once)として扱い、イベントの同一性で重複排除してください。
X-FabHub-Eventでフィルターし、処理しないイベントタイプは無視してください。