Webhook (in uscita)

Invia gli eventi di FreeMaint ai tuoi sistemi, in tempo reale

4 min di lettura
Stampa questa sezione

I webhook sono la metà «push» delle integrazioni: invece che il tuo sistema interroghi FreeMaint, è FreeMaint a fare una POST verso il tuo URL non appena accade qualcosa. Si configurano in Impostazioni azienda > Webhook (/company-settings/webhooks). Disponibili da Starter (100 consegne/giorno; illimitate da Business).

Eventi disponibili

  • work_order.created — è stato creato un ordine di lavoro
  • work_order.completed — un ordine di lavoro è passato a Completato
  • work_order.status_changed — un ordine di lavoro è passato a un qualsiasi stato; il payload porta new_status. Si attiva oltre a work_order.completed, che resta invariato
  • request.created — è stata inviata una richiesta di manutenzione
  • request.status_changed — una richiesta è stata approvata, respinta o annullata
  • part.low_stock — un ricambio è sceso al punto di riordino o sotto
  • part.out_of_stock — un ricambio è sceso a zero
  • part.low_stock_summary — un riepilogo giornaliero per azienda con i ricambi al punto di riordino o sotto, compresi quelli mai movimentati
  • part.out_of_stock_summary — lo stesso riepilogo giornaliero, per i ricambi a zero
  • part.consumed — un ricambio è stato consumato su un ordine di lavoro, o reso
  • compliance.chain_divergence — la catena di hash di audit si è interrotta (Enterprise)
  • asset.downtime_started — è stato aperto un fermo macchina
  • asset.downtime_ended — è stato chiuso un fermo macchina; la durata è ora imputabile
  • report.daily_summary — i lavori completati della giornata, una volta al giorno all'ora che scegli
  • purchase_order.created — è stato creato un ordine di acquisto; il payload contiene l'ordine (reference, status, total_cost, currency, expected_date, erp_reference) e il fornitore
  • purchase_order.status_changed — un ordine di acquisto ha cambiato stato (approvato, ordinato, annullato…); il payload contiene previous_status e new_status
  • purchase_order.received — è stata ricevuta una consegna su un ordine d'acquisto (inviato a ogni consegna, parziali comprese); il payload elenca ogni riga con quantity_ordered, quantity_received (questa consegna), quantity_received_total e quantity_remaining, oltre a receipt_id, fully_received e closed_short; new_status è PARTIALLY_RECEIVED finché si attende merce e RECEIVED quando l'ordine è completo o chiuso

part.consumed — rispecchiare il magazzino in un ERP

È l'evento a cui iscriversi quando un altro sistema (ERP, fatturazione, magazzino, contabilità) deve riflettere ciò che la manutenzione ha davvero consumato. quantity ha segno: negativo quando il ricambio esce verso il lavoro, positivo quando rientra togliendolo dall'ordine di lavoro — così uno storno in FreeMaint genera il corrispondente documento di reso a valle. stock_movement_id resta stabile tra tentativi e rinvii: usalo come chiave di idempotenza e non registrerai mai due volte la stessa uscita. Da sapere quando il traffico va in entrambe le direzioni: la mutazione GraphQL adjustStock NON attiva questo evento. È voluto — una rettifica di giacenza che il suo sistema scrive in FreeMaint non deve mai tornarle come un'eco da registrare due volte. Solo il consumo registrato su un ordine di lavoro dentro FreeMaint genera part.consumed. Il ricambio include anche custom_reference: il vostro codice, il customReference impostato con createPart o updatePart, così un sistema che gestisce il catalogo può abbinare ogni riga senza tenere una tabella degli ID FreeMaint.

{ "event": "part.consumed", "timestamp": "2026-08-19T21:04:11.000Z", "data": { "part": { "id": 812, "name": "Cuscinetto 6204", "part_number": "RLM-204", "reference": "PART-812", "custom_reference": "BC-10045", "unit_cost": 12.5, "unit_of_measure": "pz" }, "quantity": -2, "previous_quantity": 48, "new_quantity": 46, "work_order": { "id": 5521, "reference": "WO-2026-0412", "title": "Sostituzione cuscinetto" }, "asset": { "id": 91, "name": "Scrematrice 2" }, "location": { "id": 7, "name": "Magazzino stabilimento" }, "user": { "id": 5627, "name": "A. Tecnico" }, "stock_movement_id": 88213, "occurred_at": "2026-08-19T21:04:11.000Z" } }

Consegna e firma

Ogni consegna è una POST con corpo JSON e un header X-FreeMaint-Signature nella forma t=<secondi unix>,v1=<hex>, dove v1 è l'HMAC-SHA256 della stringa «<t>.<corpo grezzo>» con il segreto del webhook come chiave. Verifica sul corpo GREZZO, prima di qualsiasi parsing JSON o ri-serializzazione. Inviamo anche X-FreeMaint-Event e X-FreeMaint-Delivery-Id. Un 2xx segna la consegna come riuscita; errori di rete e 5xx vengono ritentati fino a 3 volte con backoff esponenziale (circa 2 s, 4 s, 8 s); un 4xx è considerato rifiuto definitivo e NON viene ritentato.

Rinviare una consegna

Ogni tentativo resta nello storico consegne del webhook, con stato e codice di risposta. Ogni consegna conclusa può essere rinviata da lì: viene reinviato lo stesso payload memorizzato, quindi le chiavi di business che contiene (incluso stock_movement_id) restano identiche e un ricevitore che deduplica correttamente non registrerà due volte. È così che si recupera dopo un disservizio del tuo endpoint o un rifiuto per errore.

Foto (facoltative)

Quando «Includi foto» è attivo su un webhook (disattivato per impostazione predefinita), gli oggetti "work_order" e "request" contengono un array "photos": fino a 4 link HTTPS a immagini JPG, PNG, GIF o WebP, prima le più recenti. Ogni link apre l'immagine senza accesso per 7 giorni: conserva il file sul tuo sistema se ti serve più a lungo. Un nuovo invio ripropone gli stessi link. Gli altri eventi e gli altri webhook non cambiano. Per "work_order.created" e "request.created", un webhook con «Includi foto» viene inviato 90 secondi dopo l'evento (il campo "timestamp" conserva l'ora dell'evento), per includere le foto caricate subito dopo il record.

Requisiti dell'URL

  • Solo https:// — il semplice http viene rifiutato
  • Solo porta 443 o 8443
  • L'host deve essere raggiungibile pubblicamente — intervalli loopback, privati e CGNAT vengono rifiutati
  • Nessuna credenziale nell'URL (https://utente:password@host viene rifiutato)
  • Un sistema che esiste solo nella tua rete interna richiede un endpoint pubblico o un relay (n8n, Make, Zapier) davanti

Limiti

  • Starter — 100 consegne/giorno per azienda
  • Business — illimitato
  • Enterprise — illimitato
  • Il contatore conta i tentativi di consegna: tre webhook iscritti allo stesso evento consumano tre unità
  • Il contatore giornaliero si azzera alle 00:00 UTC

Suggerimento

Verifica l'header X-FreeMaint-Signature a ogni richiesta, sul corpo grezzo, perché una chiamata contraffatta non possa movimentare il magazzino nel tuo ERP.

Questa pagina è stata utile?