GH GambleHub

Webhooks e idemoticità degli eventi

TL; DR

Un buon webhook è un evento sottoscritto (HMAC/mTLS), riassunto e idompotente, consegnato attraverso il modello at-least-once con backoff esponenziale e deduplicazione dal destinatario. Chiedi una busta («event _ id», «type», «ts», «variante», «attempt», «signature»), una finestra temporale (≤5 min), codici di risposta, retrai, DLQ e stato endpoint.


1) Ruoli e modello di consegna

Mittente (tu/provider) - Crea un evento, firma, cerca di consegnare fino a 2xx, ritrae a 3xx/4xx/5xx (tranne che esplicitamente «non accetti»), guida il DLQ, dà un'API replay.
Destinatario (partner/servizio): controlla la firma/finestra temporanea, esegue l'elaborazione di deducibili e idropotenti, risponde con codice corretto, fornisce/status e/ack replay à event _ id ".

Garanzie: at-least-once. Il destinatario deve essere in grado di elaborare duplicati e cambiare ordine.


2) Busta evento (invelope)

json
{
"event_id": "01HF7H9J9Q3E7DYT5Y6K3ZFD6M",
"type": "payout.processed",
"version": "2025-01-01",
"ts": "2025-11-03T12:34:56.789Z",
"attempt": 1,
"producer": "payments",
"tenant": "acme",
"data": {
"payout_id": "p_123",
"status": "processed",
"amount_minor": 10000,
"currency": "EUR"
}
}

I campi obbligatori sono «event _ id», «type», «variante», «ts», «attempt».
Regole di evoluzione: aggiungiamo campi; rimozione/cambio dei tipi - solo con la nuova versione.


3) Protezione: etichette e riferimenti

3. 1 firma HMAC (scelta predefinita)

Intestazioni:

X-Signature: v1=base64(hmac_sha256(<secret>, <canonical>))
X-Timestamp: 2025-11-03T12:34:56Z
X-Event-Id: 01HF7...
Stringa canonica:

<timestamp>\n<method>\n<path>\n<sha256(body)>
Controllo dal destinatario:
  • abs(now − `X-Timestamp`) ≤ 300s
  • «X-Event-Id» non è stato elaborato in precedenza (dedotto)
  • X-Firma corrisponde (con confronto a tempo sicuro)

3. 2 Dop. misure

mTLS per webhoot altamente sensibili.
IP/ASN allow-list.
DPoP (opzionale) per sender-constrained se il webhook avvia le chiamate.


4) Idampotenza e deduplicazione

4. 1 Idampotenza evento

Un evento con lo stesso «event _ id» non può cambiare di nuovo lo stato. Destinatario:
  • memorizza «event _ id» in una cache idropotente (KV/Redis/OBD) su TTL 24-72 ore;
  • salva il risultato della lavorazione (successo/errore, artefatti) per la restituzione.

4. 2 Idampotenza dei comandi (chiamate di ritorno)

Se il webhook costringe il client a scorrere l'API (ad esempio, «conferma payout»), utilizzare «Idempotency-Key» nella chiamata RESTA, memorizzare il risultato sul lato servizio (exactly-once outcome).

Modello KV (minimo):

key: idempotency:event:01HF7...
val: { status: "ok", processed_at: "...", handler_version: "..." }
TTL: 3d

5) Retrai e backoff

Grafico consigliato (esponenziale con jitter):
  • '5s, 15s, 30s, 1m, 2m, 5m, 10m, 30m, 1h, 3h, 6h, 12h, 24h' (avanti giornaliero fino a N giorni)
Soluzioni codici:
  • 2xx è un successo, interrompere i retrai.
4xx:
  • «400/ 401/403/404/422» non è retraibile se la firma/formato di ok (errore client).
  • «429» - Retraim per «Retry-After» o backoff.
  • 5xx/rete - Retraim.

Le intestazioni del mittente sono User-Agente, X-Webhook-Producer, X-Attempt.


6) Elaborazione sul lato destinatario

Pseudopipline:
pseudo verify_signature()
if abs(now - X-Timestamp) > 300s: return 401

if seen(event_id):
return 200 // идемпотентный ответ

begin transaction if seen(event_id): commit; return 200 handle(data)       // доменная логика mark_seen(event_id)    // запись в KV/DB commit return 200

Transattività: l'etichetta «seen» deve essere attivata in modo atomico con l'effetto operazione (o dopo aver bloccato il risultato) per evitare la doppia elaborazione in caso di guasto.


7) Garanzie di ordine e snapshot

L'ordine non è garantito. Utilizzare «ts» e «seq »/« variante» di dominio in «data» per verificare la rilevanza.
Per lame/perdite lunghe - Aggiungi/replay al mittente e/resync al destinatario (ricevi snap e delta alla finestra del tempo/ID).


8) Stato, replay e DLQ

8. 1 Endpoint del mittente

«POST/webhooks/replay» è nell'elenco «event _ id» o nella finestra temporale.
«GET/webhooks/events/: id» - mostra il pacchetto originale e la cronologia dei tentativi.
DLQ: eventi «morti» (esaurito il limite dei retrai) per un deposito separato, alert.

8. 2 Endpoint destinatari

`GET /webhooks/status/:event_id` — `seen=true/false`, `processed_at`, `handler_version`.
«POST/webhooks/ack» è (opzionale) la conferma della lavorazione manuale dal DLQ.


9) Contratti di errore (risposta del destinatario)

http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
Retry-After: 120
X-Trace-Id: 4e3f...

{
"error": "invalid_state",
"error_description": "payout not found",
"trace_id": "4e3f..."
}

Raccomandazioni: restituire sempre un codice chiaro e, se possibile, «Retry-After». Non restituire dettagli di sicurezza.


10) Monitoraggio e SLO

Metriche (mittente):
  • delivery p50/p95, success rate, retrai/evento, drop-rate DLQ, share 2xx/4xx/5xx, finestra di ritardo fino a 2xx.
Metriche (destinatario):
  • verify fail rate (firma/ora), dup-rate, latency handler p95, 5xx.
Punti di riferimento SLO:
  • Consegna: ≥ 99. Il 9% degli eventi riceve 2xx <3 c p95 (dopo il primo tentativo riuscito).
  • Cryptoprover: convalida firma 2-5 ms p95.
  • Deadup: 0 effetti ripetuti (exactly-once outcome a livello di dominio).

11) Sicurezza dei dati e privacy

Non trasmettere PAN/PII nel corpo del webhook; Utilizzare gli ID e i pull successivi per i dettagli dell'API autorizzata.
Mascherare i campi sensibili nei tastieri memorizzare i corpi degli eventi solo al minimo, con TTL.
Cifrare lo storage DLQ e la replica.


12) Versioning e compatibilità

Versione in versione (busta) e nel percorso: '/webhooks/v1/payments '.
Nuovi campi - opzionali; eliminazione - solo dopo il periodo Sunset.
Documentare le modifiche apportate alla machine-readable changelog (per l'automazione).


13) Valigetta di prova (foglio di assegno UAT)

  • Rifare lo stesso «event _ id» per un effetto e «200» per i duplicati.
  • Firma: chiave corretta, chiave sbagliata, vecchia chiave (rotazione), 'X-Timestamp', fuori dalla finestra.
  • Backoff: il destinatario dà «429» con «Retry-After» per una pausa corretta.
  • Ordine: Gli eventi «... processed» arrivano prima «... created» → l'elaborazione/l'attesa corretta.
  • Il target del destinatario non è riuscito tra l'effetto e l'effetto «mark _ seen».
  • Il DLQ e il replay manuale sono stati consegnati correttamente.
  • La «tempesta» di massa (il provider invia pacchetti) è senza perdita, i limiti non soffocano il critico.

14) Mini snippet

Firma mittente (pseudo):
pseudo body = json(event)
canonical = ts + "\n" + "POST" + "\n" + path + "\n" + sha256(body)
sig = base64(hmac_sha256(secret, canonical))
headers = {"X-Timestamp": ts, "X-Event-Id": event.event_id, "X-Signature": "v1="+sig}
POST(url, body, headers)
Controllo e controllo del destinatario (pseudo):
pseudo assert abs(now - X-Timestamp) <= 300 assert timingSafeEqual(hmac(secret, canonical), sig)

if kv.exists("idemp:"+event_id): return 200

begin tx if kv.exists("idemp:"+event_id): commit; return 200 handle(event.data)        // доменная логика kv.set("idemp:"+event_id, "ok", ttl=259200)
commit return 200

15) Errori frequenti

Non c'è deduplo per gli effetti ripetuti (doppi refandi/payout).
Firma senza timestamp/finestra per la vulnerabilità al replay.
Conservare un solo segreto HMAC su tutti i partner.
Le risposte «200» prima di fissare il risultato → la perdita di eventi di crash.
Lavare le parti di protezione in risposte/fogli.
Nessun DLQ/replica - Gli incidenti sono irrisolti.


16) Spargisale di implementazione

Sicurezza: HMAC v1 + 'X-Timestamp' + 'X-Event-ID', finestra 5 minuti; mTLS/IP allow-list per necessità.
Конверт: `event_id`, `type`, `version`, `ts`, `attempt`, `data`.
Consegna: at-least-once, backoff con jitter, «Retry-After», DLQ + reporter API.
Idampotenza: KV-Kash 24-72 h, effetto di fissazione atomica + 'mark _ seen'.
Osservabilità: metriche di spedizione, firme, duplicati; traccia «trace _ id».
Documentazione: versione, codici di risposta, esempi, foglio di assegno UAT.


Curriculum

I webhoot resistenti sono costruiti su tre balene: una busta firmata, una consegna at-least-once e un trattamento idoneo. Formalizzare il contratto, attivare la finestra di tempo e la finestra di tempo, implementare i retrai + DLQ e repliche, memorizzare le etichette idropotenti e registrare gli effetti dell'atomaro. Gli eventi rimangono affidabili anche in caso di guasti alla rete, picchi di carico e rari duplicati del destino.

Contact

Mettiti in contatto

Scrivici per qualsiasi domanda o richiesta di supporto.Siamo sempre pronti ad aiutarti!

Avvia integrazione

L’Email è obbligatoria. Telegram o WhatsApp — opzionali.

Il tuo nome opzionale
Email opzionale
Oggetto opzionale
Messaggio opzionale
Telegram opzionale
@
Se indichi Telegram — ti risponderemo anche lì, oltre che via Email.
WhatsApp opzionale
Formato: +prefisso internazionale e numero (ad es. +39XXXXXXXXX).

Cliccando sul pulsante, acconsenti al trattamento dei dati.