Configurare e proteggere i webhook

Configurare i webhook nella PSB: topic, sicurezza HMAC SHA256 e IP whitelisting.

I webhook sono il metodo principale per ricevere notifiche in tempo reale dalla PSB. Ad ogni evento rilevante, una fattura ricevuta, una modifica di stato, una conferma di consegna, la PSB invia una richiesta HTTP POST al proprio endpoint con i dettagli dell'evento.

Come funzionano i webhook nella PSB?

Si registra un webhook (un "hook") nella PSB con un URL e un topic. La PSB invia quindi tutti gli eventi di quel topic al proprio URL. Ogni evento contiene i dati rilevanti come payload JSON.

Creare un webhook

Nessuna interfaccia disponibile: al momento non è possibile configurare un hook tramite l'interfaccia utente della piattaforma. Gli hook vengono impostati tramite l'API o tramite il supporto eConnect. Un'interfaccia self-service per gli hook è nella roadmap (prevista per il T4 2026) e farà parte di Control (Platform 2.0): gli utenti potranno quindi creare, modificare ed eliminare gli hook autonomamente. Fino ad allora, non è previsto alcun articolo passo-passo per la configurazione manuale degli hook tramite l'API.

Registrare un hook tramite l'API:

POST /api/v1/hook

I principali elementi di configurazione:

CampoDescrizioneurlL'endpoint HTTPS a cui la PSB invia gli eventitopicIl tipo di evento che si desidera ascoltare (ad es. InvoiceReceived)secretUna chiave segreta per la verifica della firma HMAC

Nota: evita di eliminare e ricreare rapidamente hook per lo stesso partyId e topic. A causa di race condition nell'elaborazione dei task, questo può temporaneamente risultare in nessun hook attivo, causando la mancata consegna degli eventi. Attendi brevemente dopo aver eliminato un hook prima di crearne uno nuovo, oppure utilizza un aggiornamento anziché eliminare + creare.

Aggiungere un topic a un hook esistente

Vuoi aggiungere un topic aggiuntivo (ad es. InvoiceReceived) a un hook esistente? Aggiorna la configurazione webhook esistente tramite la normale API /hook in modo che il topic desiderato sia incluso nell'array topics:

{
  "topics": ["InvoiceReceived"]
}

Aggiorna l'hook esistente invece di eliminarlo e ricrearlo. Eliminare e ricreare introduce una race condition in cui gli eventi potrebbero temporaneamente non essere consegnati (vedi l'avviso sopra).

Non è self-service per i clienti non tecnici. Aggiungere un topic a un hook esistente è un'operazione tecnica: chi la esegue deve sapere dove deve puntare il webhook (l'URL dell'endpoint) e capire cos'è un webhook. Un cliente non tecnico generalmente non può farlo in modo autonomo. Coinvolgi qualcuno con competenze tecniche (IT del cliente o supporto eConnect).

Topic più utilizzati
TopicQuandoInvoiceReceivedUna fattura d'acquisto è stata ricevutaInvoiceSentUna fattura di vendita è stata inviata con successoInvoiceSentErrorUna fattura di vendita non ha potuto essere consegnataInvoiceSentRetryÈ stato avviato un tentativo di reinvioInvoiceResponseReceivedUn Invoice Response (messaggi di stato) è stato ricevutoMessageLevelStatusReceivedUn messaggio di stato MLS è stato ricevuto dalla parte mittenteMessageLevelStatusSentUn messaggio di stato MLS è stato inviato con successoOrderReceivedUn ordine d'acquisto è stato ricevuto
Message Level Status (MLS)

MLS (Message Level Status) è il successore del precedente MLR e fornisce alla parte mittente un feedback sulla ricezione e l'elaborazione di un documento. L'MLS non è abilitato di default e deve essere configurato per party tramite la capability reviews nella configurazione SMP. Una volta abilitato, la PSB lo gestisce automaticamente: come Service Provider ricevente, la PSB invia un messaggio MLS al mittente dopo la ricezione e la consegna.

Quando si inviano documenti tramite la PSB, si riceve il feedback MLS dalla parte ricevente come evento webhook sul topic MessageLevelStatusReceived. Il payload contiene tra l'altro:

CampoDescrizionedocumentIdID univoco del messaggio MLSrefToDocumentIdID del documento originaledetails.statusCodeStato Peppol: AP (accepted), RE (rejected), AB (acknowledged)details.descriptionSpiegazione del ricevente

Per ricevere messaggi MLS, l'hook Peppol deve contenere il campo mlsType. I valori possibili sono ALWAYS_SEND (inviare sempre MLS di ritorno) e FAILURE_ONLY (solo in caso di rifiuto).

Suggerimento: è possibile recuperare il documento MLS completo tramite GET /api/v1-beta/{partyId}/generic/{documentId}/download, ma il payload del webhook contiene generalmente informazioni sufficienti.

Proteggere i webhook con HMAC

La PSB protegge tutte le consegne webhook con firme HMAC SHA256. Ad ogni richiesta la PSB invia l'header:

X-EConnect-Signature: sha256={handtekening}
Implementare la verifica

Per verificare la firma:

  1. Prendere il payload JSON grezzo dalla richiesta.
  2. Calcolare l'hash HMAC SHA256 con la propria chiave segreta (la stessa fornita alla creazione dell'hook).
  3. Confrontare l'hash calcolato con il valore nell'header X-EConnect-Signature.
  4. Se corrispondono, la richiesta è autentica.
Prevenzione degli attacchi replay

Controllare anche il campo sentOn nel payload. Se questo timestamp è più vecchio di 5 minuti, rifiutare la richiesta. Questo previene attacchi replay in cui una richiesta intercettata viene riprodotta successivamente.

Opzioni di sicurezza aggiuntive

Oltre alla verifica HMAC, la PSB offre livelli di sicurezza aggiuntivi:

  • IP whitelisting: limitare le richieste in entrata agli IP di produzione PSB (104.40.188.59 e 104.47.148.207)
  • Autenticazione OAuth per webhook: la PSB può autenticarsi presso il proprio endpoint con credenziali OAuth2
  • Mutual SSL: utilizzare certificati client per l'autenticazione TLS reciproca
Ordine di priorità

Se sono configurati più hook, la PSB determina quale hook utilizzare in base a:

  1. Hook a livello di PartyId hanno precedenza sugli hook a livello di environment
  2. Topic specifici hanno precedenza sui wildcard
  3. Se più hook con filtri corrispondono allo stesso topic: vince il filtro più lungo (per numero di caratteri) -- ad esempio, un filtro con una clausola && aggiuntiva vince su un filtro più corto senza quella clausola. Questo evita la doppia consegna senza richiedere che i filtri siano reciprocamente esclusivi.
  4. A parità di priorità: hook-id come criterio di spareggio
Risoluzione dei problemi

Di seguito sono riportati i problemi più comuni con i webhook e come risolverli.

SintomoCausaSoluzioneI webhook non arrivanoEndpoint irraggiungibile (timeout 100 sec.)Richiesti HTTPS + certificato SSL valido; disabilitare la protezione CSRF sull'endpoint webhookWebhook rifiutato come non sicuroLa validazione X-EConnect-Signature fallisceVerificare il calcolo HMAC SHA256: payload × segreto → stringa esadecimale con prefisso sha256=Attacco di replay bloccatoIl campo sentOn è più vecchio di 5 minutiL'endpoint elabora troppo lentamente o l'orologio è impostato in modo errato"No such host is known" (errore DNS)Il nome host dell'endpoint webhook non è più risolvibile, ad es. dopo aver rinominato l'ambiente ERP o per un record DNS scadutoVerificare e ripristinare il record DNS del dominio dell'endpoint; recuperare gli eventi mancati tramite il batch endpointHookSentError (errore definitivo)Il PSB ha riprovato per 5 giorni senza risposta 2xxControllare i log dell'endpoint; monitorare il topic HookSentError (vedere sotto); recuperare gli eventi mancati tramite il batch endpointVecchie fatture nuovamente consegnateL'API non restituisce 2xx alla prima ricezioneL'endpoint deve sempre restituire 2xx, anche per l'elaborazione asincronaElaborazione duplicata al nuovo tentativoNessun controllo di idempotenzaUsare l'header X-EConnect-Delivery (UUID univoco) per la deduplicazione
Monitorare e recuperare da HookSentError

Il PSB invia eventi webhook (ad es. InvoiceReceived quando si riceve una fattura elettronica) all'endpoint configurato. Se l'endpoint non è raggiungibile - a causa di un timeout, un errore SSL o un errore DNS come No such host is known - il PSB riprova con backoff esponenziale per 5 giorni (timeout 100 sec. per tentativo). Ogni tentativo genera un evento HookSentRetry; dopo 5 giorni senza risposta 2xx, viene emesso HookSentError come stato finale e il PSB smette di riprovare.

Conseguenza: una fattura elettronica ricevuta non verrà consegnata al cliente finché l'endpoint è irraggiungibile, senza che il cliente se ne accorga direttamente. Azioni consigliate:

  • Configurare il monitoraggio: sottoscrivere un hook (ad es. un mail-hook) al topic HookSentError in modo che un errore di consegna definitivo venga segnalato attivamente anziéé passare inosservato. Considerare anche HookSentRetry per il rilevamento precoce.
  • Risolvere la causa principale: in caso di errore DNS, verificare e ripristinare il record DNS del dominio dell'endpoint; in caso di timeout, fare in modo che l'endpoint risponda più rapidamente (2xx entro 100 sec., elaborazione pesante in modo asincrono).
  • Recuperare gli eventi mancati: gli eventi falliti durante l'interruzione possono essere recuperati tramite il batch endpoint. La finestra di 5 giorni significa che un recupero tempestivo entro tale periodo può ancora ripristinare la consegna normale.
Best practice
  • Utilizzare sempre HTTPS per il proprio endpoint webhook
  • Implementare elaborazione idempotente: la PSB può in rari casi consegnare un evento più volte
  • Restituire rapidamente un codice di stato 2xx: la PSB considera ogni risposta non 2xx come un errore e riproverà l'evento
  • Registrare tutti gli eventi ricevuti per debugging e auditing
  • Utilizzare un sistema a coda (queue) dalla propria parte se l'elaborazione richiede tempo: confermare prima la ricezione e poi elaborare
Domande frequenti
Come si verifica un webhook in entrata con HMAC SHA256?

Prenda il corpo JSON grezzo della richiesta, calcoli l'hash HMAC SHA256 con il secret indicato al momento della creazione dell'hook e lo confronti con il valore nell'header X-EConnect-Signature (dopo il prefisso sha256=). Se corrispondono, sa che la richiesta proviene dalla PSB e non è stata modificata durante il transito.

Perché è necessario controllare il campo sentOn nel payload?

Verifichi che sentOn non sia più vecchio di 5 minuti. Se il timestamp è troppo vecchio, rifiuti la richiesta. Questo previene attacchi di tipo replay, in cui una richiesta precedentemente intercettata viene reinviata in un secondo momento, anche se la firma è tecnicamente valida.

Come si evitano problemi con l'elaborazione idempotente e i retry?

Implementi un'elaborazione idempotente dalla propria parte, poiché la PSB può in rari casi consegnare un evento più di una volta. Inoltre, restituisca rapidamente uno stato HTTP 2xx: qualsiasi altra risposta viene considerata un errore e attiva un retry. Per elaborazioni pesanti, confermi prima la ricezione e poi elabori tramite una coda.