Webhooks
Quand quelque chose se produit dans Foudra, il peut en informer un autre système en lui envoyant un message : le centre de contrôle apprend que l'entretien d'un bateau est terminé, une boutique apprend que le stock a changé. Administrateurs uniquement. Pour interroger Foudra ou y modifier des données, utilisez l'API ; les webhooks servent à être informé.
En créer un
| Champ | Signification |
|---|---|
| Name (nom) | Ce qui se trouve à l'autre bout |
| URL (URL) | Où envoyer. Elle doit être en https et joignable depuis Internet. Une adresse à l'intérieur d'un réseau privé est refusée, sauf si l'exploitant de Foudra a autorisé cet hôte |
| Events (événements) | Les événements à envoyer |
Le signing secret (secret de signature) n'est affiché qu'une fois, sur la page qui suit. Copiez-le à ce moment-là : le destinataire en a besoin pour vérifier qu'un message vient bien de Foudra.
Send test (envoyer un test) envoie un événement ping. Switch off (désactiver) arrête les envois ; les événements survenus pendant qu'un webhook est désactivé ne sont pas mis de côté pour lui. Remove (supprimer) le supprime en conservant l'historique de ses livraisons.
Événements
| Événement | Quand | data |
|---|---|---|
work_order.completed |
Toute la quantité d'un ordre de fabrication est réalisée | work_order (id, number, external_ref, quantity, quantity_done, due_at, notes) et part (id, part_number, name, is_stocked) |
stock.changed |
Tout mouvement de stock. Un transfert en compte deux | movement (id, type, quantity_delta, reference_type, reference_id, occurred_at), part, location, on_hand_here, on_hand_total |
ping |
Send test | {"hello": "world"} |
Le champ external_ref d'un ordre de fabrication permet à l'autre système de savoir à quoi correspondait le travail. Créez un entretien avec la référence « Hull 207 » et l'événement de fin le mentionnera.
Ce qui est envoyé
Un POST avec un corps JSON :
{
"id": 412,
"type": "work_order.completed",
"occurred_at": "2026-10-01T14:11:18Z",
"text": "WO-00031 completed: 1 × Class 1 service (Hull 207).",
"data": { "work_order": { "number": "WO-00031", "external_ref": "Hull 207" }, "part": { } }
}
text est une phrase destinée à un humain. Les quantités sont des chaînes, comme dans l'API.
| En-tête | Signification |
|---|---|
X-Foudra-Event |
Le type d'événement |
X-Foudra-Event-Id |
L'identifiant de l'événement, le même que id dans le corps |
X-Foudra-Delivery |
L'identifiant de cette livraison |
X-Foudra-Signature |
t=<unix time>,v1=<signature> |
Ce que doit faire le destinataire
- Répondre vite avec n'importe quel statut
2xx, et faire le travail ensuite. L'absence de réponse sous 10 secondes compte comme un échec. Les redirections ne sont pas suivies. - Vérifier la signature. Calculez un HMAC-SHA256, avec le secret de signature pour clé, sur le texte
<t>.<body>: la valeurtde l'en-tête, un point, puis le corps exactement tel que reçu. Comparez le résultat, en hexadécimal, avecv1. Refusez le message s'ils diffèrent, ou sitdate de plus de quelques minutes. - S'attendre aux doublons. Un message peut arriver deux fois. Mémorisez les identifiants des événements déjà traités et ignorez ceux que vous avez déjà vus.
import hmac, hashlib, time
def verify(secret: str, header: str, body: bytes) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
signed = parts["t"].encode() + b"." + body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
En cas d'échec
Une livraison échouée est retentée au bout d'1 minute, puis 5, 15, une heure, 3, 6 et 12 heures, et abandonnée après la huitième tentative, environ un jour plus tard. Recent deliveries (livraisons récentes) affiche chacune, son nombre de tentatives et la dernière réponse ; Send now (envoyer maintenant) en retente une immédiatement.
Après huit échecs consécutifs sans aucun succès entre eux, le webhook est désactivé et une tâche apparaît sur le tableau de bord pour en expliquer la raison. Réparez le destinataire, réactivez le webhook, et utilisez Send now sur tout ce qui a été abandonné.
Les événements sont envoyés à peu près dans l'ordre où ils se produisent, mais un événement retenté peut arriver après un événement plus récent. Utilisez occurred_at si l'ordre compte.