Webhooks (sortants)

Poussez les événements FreeMaint vers vos propres systèmes, en temps réel

4 min de lecture
Imprimer cette section

Les webhooks sont la moitié « push » des intégrations : au lieu que votre système interroge FreeMaint, c'est FreeMaint qui envoie un POST à votre URL dès qu'un événement se produit. Configuration dans Paramètres entreprise > Webhooks (/company-settings/webhooks). Disponible à partir de Starter (100 livraisons/jour ; illimité à partir de Business).

Événements disponibles

  • work_order.created — un ordre de travail a été créé
  • work_order.completed — un ordre de travail est passé à Terminé
  • work_order.status_changed — un ordre de travail a changé de statut, quel qu'il soit ; la charge utile porte new_status. Se déclenche en plus de work_order.completed, qui reste inchangé
  • request.created — une demande de maintenance a été soumise
  • request.status_changed — une demande a été approuvée, refusée ou annulée
  • part.low_stock — une pièce est descendue à son point de commande ou en dessous
  • part.out_of_stock — une pièce est tombée à zéro
  • part.low_stock_summary — un récapitulatif quotidien par entreprise listant les pièces à leur point de commande ou en dessous, y compris celles qui n'ont jamais bougé
  • part.out_of_stock_summary — le même récapitulatif quotidien, pour les pièces à zéro
  • part.consumed — une pièce a été consommée sur un ordre de travail, ou rendue
  • compliance.chain_divergence — la chaîne de hachage d'audit est rompue (Enterprise)
  • asset.downtime_started — un arrêt machine a été ouvert
  • asset.downtime_ended — un arrêt machine a été clos ; la durée peut être imputée
  • report.daily_summary — les travaux terminés de la journée, une fois par jour à l'heure que vous choisissez
  • purchase_order.created — un bon de commande a été créé ; la charge utile porte la commande (reference, status, total_cost, currency, expected_date, erp_reference) et son fournisseur
  • purchase_order.status_changed — un bon de commande a changé de statut (approuvé, commandé, annulé…) ; la charge utile porte previous_status et new_status
  • purchase_order.received — une livraison a été réceptionnée sur un bon de commande (envoyé à chaque livraison, y compris partielle) ; la charge utile liste chaque ligne avec quantity_ordered, quantity_received (cette livraison), quantity_received_total et quantity_remaining, ainsi que receipt_id, fully_received et closed_short ; new_status vaut PARTIALLY_RECEIVED tant que des marchandises sont attendues, RECEIVED une fois la commande complète ou clôturée

part.consumed — refléter le stock dans un ERP

C'est l'événement auquel s'abonner lorsqu'un autre système (ERP, facturation, inventaire, comptabilité) doit refléter ce que la maintenance a réellement consommé. quantity est signé : négatif quand la pièce est sortie pour le travail, positif quand elle est rendue en la retirant de l'ordre de travail — ainsi une annulation dans FreeMaint produit un document d'annulation correspondant en aval. stock_movement_id est stable d'une nouvelle tentative ou d'un rejeu à l'autre : utilisez-le comme clé d'idempotence et vous ne comptabiliserez jamais deux fois la même sortie. À savoir quand les échanges vont dans les deux sens : la mutation GraphQL adjustStock ne déclenche PAS cet événement. C'est volontaire — une correction de stock que votre propre système écrit dans FreeMaint ne doit jamais vous revenir en écho et être comptabilisée deux fois. Seule une consommation enregistrée sur un ordre de travail dans FreeMaint déclenche part.consumed. La pièce porte aussi custom_reference : votre propre code pour elle, le customReference posé par createPart ou updatePart, pour qu'un système maître du catalogue rapproche chaque ligne sans tenir de table des identifiants FreeMaint.

{ "event": "part.consumed", "timestamp": "2026-08-19T21:04:11.000Z", "data": { "part": { "id": 812, "name": "Roulement 6204", "part_number": "RLM-204", "reference": "PART-812", "custom_reference": "BC-10045", "unit_cost": 12.5, "unit_of_measure": "u" }, "quantity": -2, "previous_quantity": 48, "new_quantity": 46, "work_order": { "id": 5521, "reference": "WO-2026-0412", "title": "Remplacement de roulement" }, "asset": { "id": 91, "name": "Écrémeuse 2" }, "location": { "id": 7, "name": "Magasin usine" }, "user": { "id": 5627, "name": "A. Technicien" }, "stock_movement_id": 88213, "occurred_at": "2026-08-19T21:04:11.000Z" } }

Livraison et signature

Chaque livraison est un POST avec un corps JSON et un en-tête X-FreeMaint-Signature de la forme t=<secondes unix>,v1=<hex>, où v1 est le HMAC-SHA256 de la chaîne « <t>.<corps brut> » avec votre secret de webhook comme clé. Vérifiez sur le corps BRUT, avant tout parsing JSON ou ré-sérialisation. Nous envoyons aussi X-FreeMaint-Event et X-FreeMaint-Delivery-Id. Un 2xx marque la livraison comme livrée ; les erreurs réseau et les 5xx sont réessayés jusqu'à 3 fois avec un back-off exponentiel (environ 2 s, 4 s, 8 s) ; un 4xx est traité comme un refus définitif et n'est PAS réessayé.

Rejouer une livraison

Chaque tentative est conservée dans l'historique de livraison du webhook, avec son statut et son code de réponse. Toute livraison terminée peut y être rejouée : elle renvoie la charge utile stockée telle quelle, donc les clés métier qu'elle contient (dont stock_movement_id) restent identiques et un récepteur qui déduplique correctement ne comptabilisera pas deux fois. C'est ainsi que l'on rattrape une panne de votre point de terminaison ou un refus par erreur.

Photos (facultatif)

Quand « Inclure les photos » est activé sur un webhook (désactivé par défaut), les objets "work_order" et "request" portent un tableau "photos" : jusqu'à 4 liens HTTPS vers des images JPG, PNG, GIF ou WebP, les plus récentes d'abord. Chaque lien ouvre l'image sans connexion pendant 7 jours : conservez le fichier de votre côté si vous en avez besoin plus longtemps. Un rejeu renvoie les mêmes liens. Les autres événements et les autres webhooks ne changent pas. Pour "work_order.created" et "request.created", un webhook avec « Inclure les photos » est envoyé 90 secondes après l'événement (le champ "timestamp" garde l'heure de l'événement), pour inclure les photos envoyées juste après la fiche.

Contraintes sur l'URL

  • https:// uniquement — le http simple est refusé
  • Port 443 ou 8443 uniquement
  • L'hôte doit être joignable publiquement — les plages loopback, privées et CGNAT sont refusées
  • Pas d'identifiants dans l'URL (https://user:pass@hote est refusé)
  • Un système qui n'existe que dans votre réseau interne a besoin d'un point d'entrée public ou d'un relais (n8n, Make, Zapier) devant lui

Plafonds

  • Starter — 100 livraisons/jour et par entreprise
  • Business — illimité
  • Enterprise — illimité
  • Le compteur porte sur les tentatives de livraison : trois webhooks abonnés au même événement consomment trois unités
  • Le compteur quotidien est remis à zéro à 00:00 UTC

Astuce

Vérifiez l'en-tête X-FreeMaint-Signature à chaque requête, sur le corps brut, pour qu'un appel usurpé ne puisse pas mouvementer le stock de votre ERP.

Cette page vous a-t-elle été utile ?