Webhook eventi
Il webhook outbound di Audin Mail — ricevere sugli endpoint dei tuoi sistemi gli eventi delle email inviate (consegne, aperture, click, bounce), verificare la firma HMAC, gestire retry e idempotenza, ruotare il signing secret.
Versione Markdown di questa pagina
Scarica o copia il contenuto di questa pagina in formato .md — utile per fornirlo a un agente AI che integra questa specifica feature.
Audin Mail può inoltrare in tempo reale a un tuo endpoint HTTPS ogni evento delle email inviate dall'account: consegne, aperture, click, bounce, segnalazioni spam. Utile per CRM esterni, sistemi di BI o automazioni sui tuoi sistemi.
Si configura da Impostazioni → Audin Mail → "Webhook outbound" (l'integrazione deve essere attiva): inserisci l'URL, premi "Configura e genera secret" e salva subito il signing secret — è mostrato una sola volta. Dalla stessa card puoi attivare/disattivare il webhook, modificare l'URL, aggiungere header custom, inviare un evento di test e consultare le ultime consegne con payload e risposta del tuo endpoint.
Requisiti dell'endpoint
- HTTPS obbligatorio, raggiungibile da internet pubblico.
- Accetta
POSTcon corpoapplication/json. - Risponde con un 2xx entro 10 secondi (elabora in asincrono se serve).
Cosa ricevi
Gli eventi arrivano in batch: una richiesta può contenere più eventi.
{
"audin_event_id": "evt_…",
"audin_account_id": "…",
"received_at": "2026-08-17T10:15:00.000Z",
"version": "1",
"events": [
{
"audin_message_id": "8b1f…",
"sendgrid": {
"event": "delivered",
"email": "cliente@esempio.it",
"timestamp": 1755425700
}
}
]
}audin_message_idè la chiave di correlazione con l'email inviata da Audin (può esserenullper eventi non riconducibili a un invio, es. l'evento di test).sendgridè il payload originale del fornitore di recapito, inoltrato così com'è: il nome della chiave fa parte del contratto e non cambia. I campi utili sonoevent(tipo evento),email,timestamp, ed eventualireason(bounce),url(click).- Tipi di evento inoltrati:
processed,delivered,open,click,bounce,dropped,deferred,spamreport. - Un bump di
version(oggi"1") segnalerà eventuali cambi di formato incompatibili.
Header di ogni richiesta
| Header | Contenuto |
|---|---|
User-Agent | Audin-Mail-Webhook/1.0 |
X-Audin-Webhook-Id | Identificativo fisso del webhook del tuo account |
X-Audin-Delivery-Id | Identificativo della singola consegna — usalo come chiave di idempotenza (i retry lo ripetono) |
X-Audin-Signature-Timestamp | Unix timestamp (secondi) usato nella firma |
X-Audin-Signature | v1=<hex> — firma HMAC-SHA256 (vedi sotto) |
Gli eventuali header custom configurati (max 5) vengono aggiunti a ogni richiesta.
Verifica della firma (obbligatoria)
Ogni richiesta è firmata: verifica sempre la firma prima di fidarti del contenuto.
signed_payload = timestamp + "." + corpo_raw_della_richiestaatteso = HMAC_SHA256(secret, signed_payload)in esadecimale- confronta (in constant-time) con il valore dopo
v1=nell'header - anti-replay: rifiuta richieste con timestamp più vecchio di 5 minuti
La firma va calcolata sul corpo raw della richiesta, non sul JSON
ri-serializzato: qualsiasi middleware che fa il parse del body prima della
verifica (es. express.json()) la invalida.
const crypto = require("crypto");
const express = require("express");
const app = express();
app.post("/audin/webhook",
express.raw({ type: "application/json" }), // body RAW, non json()
(req, res) => {
const ts = req.header("X-Audin-Signature-Timestamp");
const sig = req.header("X-Audin-Signature"); // "v1=<hex>"
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
return res.status(400).send("timestamp too old");
}
const expected = "v1=" + crypto
.createHmac("sha256", process.env.AUDIN_WEBHOOK_SECRET)
.update(`${ts}.${req.body.toString("utf8")}`)
.digest("hex");
const ok = sig && crypto.timingSafeEqual(
Buffer.from(sig), Buffer.from(expected));
if (!ok) return res.status(401).send("bad signature");
const payload = JSON.parse(req.body.toString("utf8"));
// elabora payload.events in asincrono, poi:
res.sendStatus(200);
});import hashlib, hmac, os, time
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/audin/webhook")
def audin_webhook():
ts = request.headers.get("X-Audin-Signature-Timestamp", "")
sig = request.headers.get("X-Audin-Signature", "")
raw = request.get_data() # body RAW, non request.json
if abs(time.time() - int(ts or 0)) > 300:
abort(400)
expected = "v1=" + hmac.new(
os.environ["AUDIN_WEBHOOK_SECRET"].encode(),
f"{ts}.".encode() + raw,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(sig, expected):
abort(401)
# elabora in asincrono, poi:
return "", 200Risposta attesa e retry
- Qualunque 2xx = consegna riuscita.
- 410 Gone = "non inviarmi più questo": la consegna viene marcata fallita senza retry.
- Ogni altro errore (4xx, 5xx, timeout oltre 10s, DNS irraggiungibile) attiva i retry: 6 tentativi in tutto — il primo immediato, poi dopo 1 minuto, 5 minuti, 30 minuti, 2 ore e 12 ore (circa 15 ore complessive) — dopodiché la consegna è marcata Fallita.
- I retry ripetono lo stesso
X-Audin-Delivery-Id: rendi l'elaborazione idempotente su quella chiave. - Nella card "Ultime consegne" vedi ogni tentativo con stato HTTP, durata e corpo della risposta del tuo endpoint (troncato).
Rotazione del signing secret
"Rigenera" genera un nuovo secret, attivo immediatamente: Audin firma da subito solo col nuovo. Il precedente resta consultabile per 24 ore a fini di supporto. Procedura senza downtime: predisponi la verifica a doppio secret (o preparati ad aggiornare l'env), clicca "Rigenera", salva il nuovo secret (mostrato una volta sola) e aggiornalo nei tuoi sistemi.
Test in sviluppo
Per sviluppare in locale esponi l'endpoint con un tunnel (ngrok, Cloudflare
Tunnel) o ispeziona i payload con un servizio tipo webhook.site. Il
pulsante "Invia evento di test" fa una POST sincrona (evento
event: "test", audin_message_id: null) e mostra subito status, durata e
risposta — senza retry.
Checklist di sicurezza
- endpoint solo HTTPS, secret in un secret manager (mai nel codice);
- verifica HMAC in constant-time su ogni richiesta + anti-replay 5 min;
- risposta 2xx entro 10 secondi, elaborazione asincrona;
- idempotenza su
X-Audin-Delivery-Id; - gli header custom non sostituiscono la verifica della firma.
Prossimi passi
Broadcast
Inviare un'email massiva a una lista filtrata di lead con Audin Mail — l'anteprima con destinatari, costo, credito e quota, il ritmo di invio, e il monitoraggio con pausa, ripresa e annullamento.
Booking
I link di prenotazione — durata, buffer e preavvisi, calendari sorgente e di destinazione, la logica di disponibilità con verifica live sui calendari Google, le tipologie di incontro e il link di default per i bot.