Webhook duplicati o fuori ordine: una prova per rendere affidabile il collegamento al gestionale

Parliamo del tuo progetto →

Ricevere un webhook non significa riceverlo una sola volta, né nell’ordine in cui il provider lo ha generato. Stripe documenta che gli eventi possono essere ritentati, arrivare più volte e non rispettare l’ordine di consegna; per questo un’integrazione verso il gestionale va progettata come un flusso idempotente e riconciliabile, non come una semplice ricezione di messaggi. (docs.stripe.com)

Perché questo tema conta quando un provider aggiorna un gestionale

Il problema non riguarda solo i pagamenti. Ogni volta che un sistema esterno invia eventi a un gestionale — ordine aggiornato, abbonamento rinnovato, pagamento completato, documento emesso — il rischio operativo è lo stesso: duplicati, ritardi e messaggi fuori ordine possono portare a uno stato incoerente.

La differenza tra un prototipo e un’integrazione affidabile sta qui: il sistema non deve fidarsi dell’ordine di arrivo sulla rete, ma del proprio stato interno e dello stato autorevole dell’oggetto lato provider. Stripe indica anche che, se manca un evento, si possono recuperare gli oggetti via API; questa è una strategia di riconciliazione, non una promessa di consegna “esattamente una volta”. (docs.stripe.com)

Prerequisiti prima di iniziare

Prima di costruire il collegamento, servono almeno tre elementi:

  • un endpoint HTTPS pubblico che riceva i webhook;
  • la chiave segreta del webhook, usata per verificare la firma Stripe-Signature;
  • una regola di dominio chiara: quale stato del gestionale deve cambiare, con quale evento e con quali eccezioni.

Stripe specifica che la verifica deve usare il body grezzo della richiesta; se il contenuto viene modificato prima del controllo, la firma non risulta valida. Inoltre raccomanda di rispondere rapidamente con un 2xx, rimandando il lavoro più pesante a un processo successivo. (docs.stripe.com)

Caso simulato: un ordine aggiornato fuori sequenza

Un connettore aggiorna il gestionale quando cambia lo stato di un ordine. Nel test arrivano tre notifiche: prima quella più recente, poi una più vecchia, infine una copia della prima.

Obiettivo atteso

Il gestionale deve finire nello stato corretto e non deve applicare due volte lo stesso effetto. Un evento vecchio non deve riportare il sistema a una condizione superata.

Input concreto di prova

  • Evento A: order.updated con stato finale spedito
  • Evento B: order.updated precedente con stato in preparazione
  • Evento A duplicato: stessa notifica già vista

Nota: questi nomi sono esempi didattici, non payload reali della documentazione Stripe.

I tre controlli da separare sempre

1) Autenticità della notifica

Prima di tutto si verifica che il messaggio provenga davvero dal provider. Con Stripe questo significa controllare Stripe-Signature, usare il raw body e il secret corretto. La deduplicazione non sostituisce la verifica della firma: un evento duplicato può essere autentico oppure no, e i due controlli rispondono a domande diverse. (docs.stripe.com)

2) Deduplicazione persistente

Stripe segnala che gli eventi possono arrivare più di una volta e suggerisce di registrare gli event.id già processati; in alcuni casi può essere utile combinare l’ID dell’oggetto in data.object con event.type. Questo dato va salvato in modo persistente, non solo in memoria, perché un riavvio cancellerebbe la prova del passaggio precedente. (docs.stripe.com)

3) Presa in carico affidabile

La risposta 2xx non dovrebbe essere una scorciatoia per “ho letto il messaggio”, ma l’esito di una presa in carico minima già sicura. Stripe raccomanda di rispondere velocemente; quindi la parte lunga — aggiornamento del gestionale, notifiche interne, eventuale riconciliazione via API — va spostata fuori dal percorso sincrono. (docs.stripe.com)

Procedura di prova

  1. Attiva un endpoint di test e inoltra eventi dal sandbox o dalla CLI, come indicato da Stripe. (docs.stripe.com)
  2. Invia lo stesso evento due volte. Verifica che il secondo passaggio venga riconosciuto come duplicato.
  3. Inverti l’ordine di due eventi correlati. Verifica che il sistema non adotti uno stato più vecchio come se fosse il più recente.
  4. Interrompi il servizio tra ricezione e aggiornamento del gestionale. Questo è un guasto simulato: serve a controllare se il ripristino mantiene coerenza tra evento ricevuto e effetto applicato.
  5. Recupera lo stato dal provider via API, se un evento risulta mancante o ambiguo. Stripe prevede questa possibilità come riconciliazione. (docs.stripe.com)

Controlli di accettazione

Il laboratorio è riuscito se, alla fine:

  • ogni evento valido è verificato con firma corretta;
  • ogni evento duplicato è ignorato senza effetti collaterali;
  • l’ordine finale del gestionale corrisponde alle regole del dominio, non all’ordine di arrivo;
  • gli eventi non elaborabili finiscono in una coda o in una procedura di recupero definita;
  • chi controlla il flusso sa dove guardare: log, coda, stato persistente, esito della riconciliazione.

Limiti da dichiarare apertamente

Questo tipo di test non dimostra una consegna “esattamente una volta”. Dimostra qualcosa di più utile in produzione: che il flusso resta coerente anche quando il provider ritenta, riordina o ripete una notifica. È una differenza importante, perché sposta l’attenzione dalla promessa del trasporto alla qualità dell’integrazione.

Per un gestionale, il punto non è “ricevere tutto”, ma “terminare nel giusto stato e saperlo dimostrare”. Se il processo coinvolge ordini, abbonamenti o fatture, il passo successivo è mappare un solo evento critico e definire con precisione quale effetto deve produrre nel sistema interno.

Sintesi delle fonti

Stripe documenta firma, retry, ordine non garantito, duplicati e recupero via API per i webhook. (docs.stripe.com)

Fonti