Referenz
Webhook-Anfragen
Das genaue Format von Webhook-Anfragen von Emailit, von Methode und Headern bis zum JSON-Array der Events, außerdem Reihenfolge, Duplikate und wie Sie antworten.
Diese Seite beschreibt, was an Ihrem Endpunkt ankommt: die HTTP-Anfrage, ihre Header, den JSON-Body und was Emailit als Antwort erwartet. Nutzen Sie sie, wenn Sie einen Webhook-Handler schreiben oder debuggen.
Anfrage
| Eigenschaft | Wert |
|---|---|
| Methode | POST |
| Body | Ein JSON-Array mit 1 bis 100 Events, kompakt (ohne zusätzliche Leerzeichen) |
| Timeout | 30 Sekunden |
| Redirects | Werden nicht verfolgt. Eine 3xx-Antwort gilt als Fehlschlag. |
| Parallelität | Eine Anfrage gleichzeitig pro Webhook. Batches werden nacheinander gesendet. |
| Latenz | Emailit prüft alle paar Sekunden auf neue Events, daher kommen die meisten Events innerhalb von Sekunden an. |
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 | Beschreibung |
|---|---|
Content-Type |
Immer application/json. |
User-Agent |
Immer Emailit-Webhooks/2.0. |
X-Emailit-Signature |
Hexadezimal kodierter HMAC-SHA256 von {timestamp}.{raw body}, mit dem vollständigen Secret des Webhooks (einschließlich whsec_) als Schlüssel. Siehe Anfragesignatur. |
X-Emailit-Timestamp |
Unix-Zeit in Sekunden, zu der Emailit die Anfrage signiert hat. Jeder Versuch, auch jede Wiederholung, wird mit einem neuen Zeitstempel erneut signiert. |
Body
Der Body ist immer ein JSON-Array, auch wenn er nur ein einzelnes Event enthält. Jedes Element hat diese Form:
| Feld | Typ | Beschreibung |
|---|---|---|
event_id |
string | Die ID des Events, beginnend mit evt_. Dasselbe Event behält über Wiederholungen hinweg dieselbe ID. Test-Events beginnen mit evt_test_. |
type |
string | Der Event-Typ, etwa email.delivered. |
object |
object | Die Ressource, um die es im Event geht. |
data |
object | Enthält object noch einmal. data.object und das object der obersten Ebene sind identisch; lesen Sie, welches Sie bevorzugen. |
Die Felder in object hängen vom Typ ab. E-Mail-Status-Events beschreiben die E-Mail; email.clicked und email.loaded beschreiben den Klick oder Ladevorgang und enthalten die E-Mail verschachtelt; Ressourcen-Events wie contact.created beschreiben die Ressource.
Beispiel-Batch
Diese Anfrage enthält zwei Events: eine Zustellung und einen späteren Klick auf einen Link in derselben E-Mail.
[
{
"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"
}
}
}
]Zeitstempel sind im Format ISO 8601 in UTC angegeben. meta enthält die Metadaten, die Sie beim Senden angehängt haben, oder null. contact ist null, wenn der Empfänger keiner Ihrer Kontakte ist, und campaign ist bei E-Mails per API und SMTP null.
Reihenfolge
Innerhalb einer Anfrage sind die Events nach Alter geordnet, die ältesten zuerst. Über Anfragen hinweg gibt es keine Garantie für die Reihenfolge: Ein fehlgeschlagener Batch wird später wiederholt, während neuere Events womöglich schon angekommen sind, und eine manuelle Wiederholung kann alte Events nach neuen erneut senden.
Verlassen Sie sich nicht auf die Ankunftsreihenfolge. Verwenden Sie bei E-Mail-Events status und updated_at der E-Mail und behalten Sie den am weitesten fortgeschrittenen Zustand, den Sie gesehen haben (überschreiben Sie zum Beispiel clicked nicht mit einem verspäteten delivered). Rufen Sie im Zweifel den aktuellen Zustand mit E-Mail abrufen ab.
Duplikate
Dasselbe Event kann mehrfach ankommen:
- Wenn Ihr Endpunkt nach der Verarbeitung eines Teils eines Batches in ein Timeout läuft oder einen Fehler zurückgibt, wird der ganze Batch wiederholt, einschließlich der Events, die Sie bereits verarbeitet haben.
- Wenn Sie Retry failed verwenden oder eine einzelne Anfrage wiederholen.
Speichern Sie jede verarbeitete event_id mit einem Unique-Constraint und überspringen Sie Events, die Sie bereits gesehen haben.
Antworten
| Ihre Antwort | Ergebnis |
|---|---|
Jede 2xx-Antwort innerhalb von 30 Sekunden |
Jedes Event im Batch wird als Delivered markiert. Der Antwort-Body wird ignoriert. |
3xx, 4xx oder 5xx |
Der Batch ist fehlgeschlagen und wird wiederholt. |
| Keine Antwort innerhalb von 30 Sekunden, Verbindungsfehler, TLS-Fehler | Der Batch ist fehlgeschlagen und wird wiederholt. Die Weboberfläche zeigt den Statuscode 0. |
Bei fehlgeschlagenen Anfragen speichert Emailit die ersten 2.000 Zeichen Ihres Antwort-Bodys. Sie können ihn im Tab Requests des Webhooks lesen; eine kurze Fehlermeldung in der Antwort hilft daher beim Debuggen.
Empfehlungen:
- Erst verifizieren, dann schnell bestätigen. Prüfen Sie die Signatur, legen Sie die Events in eine Warteschlange oder Tabelle und geben Sie
200zurück. Erledigen Sie langsame Arbeit, etwa Aufrufe anderer APIs, in einem Hintergrundjob. - Auch für ignorierte Events
2xxzurückgeben. Andernfalls werden sie tagelang wiederholt. - Bei ungültiger Signatur
401oder403zurückgeben. Die Anfrage wird wie jeder Fehlschlag wiederholt, was Ihnen Zeit gibt, ein falsch konfiguriertes Secret zu korrigieren.
Den Wiederholungsplan und was passiert, wenn ein Endpunkt dauerhaft fehlschlägt, finden Sie unter Wiederholungen und Fehlschläge.