Webhooks
Les webhooks délivrent des requêtes POST sortantes signées pour certains événements du tenant, ce qui vous permet de réagir aux changements sans interrogation. Gérez les endpoints depuis Settings -> Integrations -> Webhooks ou via l'API publique.
Événements
| Événement | Statut | Livraison |
|---|---|---|
inventory.item.created | Émis | Livraison signée par outbox |
inventory.item.updated | Émis | Livraison signée par outbox |
order.created | Émis | Livraison signée par outbox |
order.updated | Émis | Livraison signée par outbox |
contact.created | Émis | Livraison signée par outbox |
contact.updated | Émis | Livraison signée par outbox |
stock_document.created | Émis | Livraison signée par outbox |
stock_document.updated | Émis | Livraison signée par outbox |
user.invited | Émis | Livraison signée par outbox |
organization.updated | Émis | Livraison signée par outbox |
integration.connected | Émis | Livraison signée par outbox |
bom.created | Planifié | Réservé au contrat, pas encore émis |
bom.updated | Planifié | Réservé au contrat, pas encore émis |
webhook.test | Test uniquement | Vérification de connectivité non signée |
S'abonner
Créez un endpoint avec POST /v1/webhooks (scope webhooks:write, Enterprise). Le secret de signature est renvoyé une seule fois dans la réponse - stockez-le immédiatement.
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"
}
Format de livraison
Chaque livraison est un POST contenant le corps JSON de l'événement et ces en-têtes :
X-FabHub-Event- le type d'événement, par exempleorder.createdX-FabHub-Timestamp- secondes unix au moment de la signature de la charge utileX-FabHub-Signature- HMACv1=<hex>; plusieurs partiesv1=séparées par des virgules apparaissent pendant la rotation du secret
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" } }
Vérifier la signature
La signature est HMAC-SHA256(secret, "<timestamp>.<rawBody>"), encodée en hexadécimal, où secret est votre secret de signature décodé depuis l'hexadécimal. Vérifiez toujours par rapport au corps brut exact de la requête, avant l'analyse JSON. Le SDK fournit un vérificateur :
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
Rotation du secret
Effectuez la rotation avec PATCH /v1/webhooks/{webhook_id} et {"rotateSecret": true}. Le nouveau secret est renvoyé une seule fois et, pendant la fenêtre de chevauchement, les livraisons sont signées avec le nouveau et le précédent secret (transmettez les deux au vérificateur via signingSecrets).
Journaux de livraison
Inspectez les tentatives avec GET /v1/webhooks/{webhook_id}/deliveries (scope 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 }
}
Les pings de test synthétiques (webhook.test) sont des vérifications de connectivité non signées et n'apparaissent pas dans le journal de l'outbox.
Bonnes pratiques
- Renvoyez
2xxrapidement ; effectuez le travail lourd de façon asynchrone. - Traitez la livraison comme étant au moins une fois et dédupliquez sur l'identité de l'événement.
- Filtrez sur
X-FabHub-Eventet ignorez les types d'événements que vous ne gérez pas.