웹훅
웹훅은 선택된 테넌트 이벤트에 대해 서명된 아웃바운드 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.createdX-FabHub-Timestamp- 페이로드가 서명된 시점의 유닉스 초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" } }
서명 검증
서명은 16진수로 인코딩된 HMAC-SHA256(secret, "<timestamp>.<rawBody>")이며, 여기서 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 }
}
합성 테스트 핑(webhook.test)은 서명되지 않은 연결 확인이며 아웃박스 로그에 나타나지 않습니다.
모범 사례
2xx를 신속하게 반환하고, 무거운 작업은 비동기적으로 수행하세요.- 전달을 적어도 한 번(at-least-once)으로 취급하고 이벤트 식별자로 중복을 제거하세요.
X-FabHub-Event로 필터링하고 처리하지 않는 이벤트 유형은 무시하세요.