Riferimento
Richieste webhook
Il formato esatto delle richieste webhook di Emailit, dal metodo e dagli header all’array JSON di eventi, più ordine, duplicati e come rispondere.
Questa pagina descrive cosa arriva al tuo endpoint: la richiesta HTTP, i suoi header, il corpo JSON e cosa si aspetta Emailit in risposta. Usala quando scrivi o esegui il debug di un gestore di webhook.
Richiesta
| Proprietà | Valore |
|---|---|
| Metodo | POST |
| Corpo | Un array JSON da 1 a 100 eventi, compatto (senza spazi superflui) |
| Timeout | 30 secondi |
| Reindirizzamenti | Non vengono seguiti. Una risposta 3xx conta come errore. |
| Concorrenza | Una richiesta alla volta per webhook. I batch vengono inviati uno dopo l’altro. |
| Latenza | Emailit controlla la presenza di nuovi eventi ogni pochi secondi, quindi la maggior parte degli eventi arriva in pochi secondi. |
POST /webhooks/emailit HTTP/1.1
Host: acme.com
Content-Type: application/json
User-Agent: Emailit-Webhooks/2.0
X-Emailit-Signature: 7242b580f77ec488f8ac21b57f092e3db61a431694f13074c7b4c85a4dd04be3
X-Emailit-Timestamp: 1790846045Header
| Header | Descrizione |
|---|---|
Content-Type |
Sempre application/json. |
User-Agent |
Sempre Emailit-Webhooks/2.0. |
X-Emailit-Signature |
HMAC-SHA256 in esadecimale di {timestamp}.{raw body}, calcolato con il secret completo del webhook (compreso whsec_). Vedi Firma delle richieste. |
X-Emailit-Timestamp |
Ora Unix in secondi in cui Emailit ha firmato la richiesta. Ogni tentativo, compresi i nuovi tentativi, viene firmato di nuovo con un nuovo timestamp. |
Corpo
Il corpo è sempre un array JSON, anche quando contiene un solo evento. Ogni elemento ha questa forma:
| Campo | Tipo | Descrizione |
|---|---|---|
event_id |
string | L’ID dell’evento, che inizia con evt_. Lo stesso evento mantiene lo stesso ID tra un tentativo e l’altro. Gli eventi di test iniziano con evt_test_. |
type |
string | Il tipo di evento, come email.delivered. |
object |
object | La risorsa a cui si riferisce l’evento. |
data |
object | Contiene di nuovo object. data.object e l’object di primo livello sono identici: leggi quello che preferisci. |
I campi dentro object dipendono dal tipo. Gli eventi di stato delle email descrivono l’email; email.clicked e email.loaded descrivono il clic o il caricamento e annidano l’email; gli eventi delle risorse, come contact.created, descrivono la risorsa.
Esempio di batch
Questa richiesta contiene due eventi: una consegna e un clic successivo su un link della stessa email.
[
{
"event_id": "evt_2xGk7Nq1VbD5sR8tLmW3eYhC6aP",
"type": "email.delivered",
"object": {
"id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"object": "email",
"from": "billing@acme.com",
"to": "ada@example.com",
"subject": "Your receipt #1042",
"status": "delivered",
"meta": { "order_id": "1042" },
"updated_at": "2026-10-01T09:14:03.512000+00:00",
"created_at": "2026-10-01T09:14:01.207000+00:00"
},
"data": {
"object": {
"id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"object": "email",
"from": "billing@acme.com",
"to": "ada@example.com",
"subject": "Your receipt #1042",
"status": "delivered",
"meta": { "order_id": "1042" },
"updated_at": "2026-10-01T09:14:03.512000+00:00",
"created_at": "2026-10-01T09:14:01.207000+00:00"
}
}
},
{
"event_id": "evt_2xGkC8w2TnF4yR7bMqL1sVdJ6pE",
"type": "email.clicked",
"object": {
"id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
"object": "click",
"email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"email": {
"id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"rcpt_to": "ada@example.com",
"mail_from": "billing@acme.com",
"subject": "Your receipt #1042",
"created_at": "2026-10-01T09:14:01.207000+00:00",
"campaign": null,
"meta": { "order_id": "1042" }
},
"link": {
"id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
"url": "https://acme.com/orders/1042"
},
"contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
"ip_address": "203.0.113.24",
"user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
"created_at": "2026-10-01T09:20:47.884000+00:00"
},
"data": {
"object": {
"id": "click_2xGkC7v5PmD3xQ9aLnK2rUcH8oW",
"object": "click",
"email_id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"email": {
"id": "em_2xGk7Lr3XcB8pQ1wYzK4dTfG9hJ",
"rcpt_to": "ada@example.com",
"mail_from": "billing@acme.com",
"subject": "Your receipt #1042",
"created_at": "2026-10-01T09:14:01.207000+00:00",
"campaign": null,
"meta": { "order_id": "1042" }
},
"link": {
"id": "link_2xGk7Mb6QwE1zS8cNpT4vXfK3gB",
"url": "https://acme.com/orders/1042"
},
"contact": { "id": "con_2xFh3Ka9LmP2nR6tVwB8cDqY5sZ", "email": "ada@example.com" },
"ip_address": "203.0.113.24",
"user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X)",
"created_at": "2026-10-01T09:20:47.884000+00:00"
}
}
}
]I timestamp sono in formato ISO 8601 in UTC. meta contiene i metadati che hai allegato all’invio, oppure null. contact è null quando il destinatario non è uno dei tuoi contatti, e campaign è null per le email inviate via API e SMTP.
Ordine
All’interno di una richiesta, gli eventi sono ordinati dal meno recente. Tra richieste diverse l’ordine non è garantito: un batch non riuscito viene ritentato più tardi, quando eventi più recenti potrebbero essere già arrivati, e un nuovo tentativo manuale può reinviare eventi vecchi dopo quelli nuovi.
Non fare affidamento sull’ordine di arrivo. Per gli eventi delle email, usa status e updated_at dell’email e conserva lo stato più avanzato che hai visto (ad esempio, non sovrascrivere clicked con un delivered arrivato in ritardo). Nel dubbio, recupera lo stato attuale con Recupera un’email.
Duplicati
Lo stesso evento può arrivare più di una volta:
- Quando il tuo endpoint va in timeout o restituisce un errore dopo aver elaborato una parte di un batch, viene ritentato l’intero batch, compresi gli eventi che hai già gestito.
- Quando usi Retry failed o ritenti una singola richiesta.
Memorizza ogni event_id che hai elaborato, con un vincolo di unicità, e salta gli eventi che hai già visto.
Risposta
| La tua risposta | Risultato |
|---|---|
Qualsiasi 2xx entro 30 secondi |
Ogni evento del batch viene contrassegnato come Delivered. Il corpo della risposta viene ignorato. |
3xx, 4xx o 5xx |
Il batch non è riuscito e viene ritentato. |
| Nessuna risposta entro 30 secondi, errore di connessione, errore TLS | Il batch non è riuscito e viene ritentato. Il pannello mostra il codice di stato 0. |
Per le richieste non riuscite, Emailit conserva i primi 2000 caratteri del corpo della tua risposta. Puoi leggerli nella scheda Requests del webhook, quindi restituire un breve messaggio di errore è utile per il debug.
Consigli:
- Verifica, poi conferma subito. Controlla la firma, metti gli eventi in una coda o in una tabella e restituisci
200. Svolgi il lavoro lento, come chiamare altre API, in un job in background. - Restituisci
2xxper gli eventi che ignori. Altrimenti vengono ritentati per giorni. - Restituisci
401o403per una firma non valida. Viene ritentata come qualsiasi errore, e questo ti dà il tempo di correggere un secret configurato male.
Vedi Nuovi tentativi ed errori per il calendario dei nuovi tentativi e per cosa succede quando un endpoint continua a non rispondere correttamente.