Webhooks im PSB konfigurieren: Topics, HMAC SHA256-Sicherheit und IP-Whitelisting.
Webhooks sind die primäre Methode, um Echtzeit-Benachrichtigungen vom PSB zu empfangen. Bei jedem relevanten Ereignis (eine empfangene Rechnung, eine Statusänderung, eine Zustellbestätigung) sendet der PSB eine HTTP POST-Anfrage an Ihren Endpoint mit den Details des Events.
Sie registrieren einen Webhook (einen "Hook") im PSB mit einer URL und einem Topic. Der PSB sendet dann alle Events für dieses Topic an Ihre URL. Jedes Event enthält die relevanten Daten als JSON-Payload.
Keine UI verfügbar: Es ist derzeit nicht möglich, einen Hook über die Benutzeroberfläche der Plattform zu konfigurieren. Hooks werden über die API oder über den eConnect-Support eingerichtet.
Registrieren Sie einen Hook über die API:
POST /api/v1/hook
Die wichtigsten Konfigurationselemente:
InvoiceReceived)Achtung: Vermeiden Sie das schnelle Hintereinander-Löschen und Neuanlegen von Hooks für dieselbe partyId und dasselbe Topic. Durch Race Conditions in der Aufgabenverarbeitung kann es vorkommen, dass vorübergehend kein aktiver Hook existiert und Events nicht zugestellt werden. Warten Sie nach dem Löschen eines Hooks einen Moment, bevor Sie einen neuen anlegen, oder verwenden Sie ein Update statt Löschen und Neuanlegen.
Möchten Sie einem bestehenden Hook ein weiteres Topic (z. B. InvoiceReceived) hinzufügen? Aktualisieren Sie die bestehende Webhook-Konfiguration über die reguläre /hook-API, sodass das gewünschte Topic im topics-Array enthalten ist:
{
"topics": ["InvoiceReceived"]
}
Aktualisieren Sie den bestehenden Hook, anstatt ihn zu löschen und neu anzulegen. Löschen und Neuanlegen führt zu einer Race Condition, bei der Events vorübergehend nicht zugestellt werden können (siehe Warnung oben).
Kein Self-Service für nicht-technische Kunden. Das Hinzufügen eines Topics zu einem bestehenden Hook ist eine technische Aufgabe: Die ausführende Person muss wissen, wohin der Webhook gehen soll (die Endpoint-URL), und verstehen, was ein Webhook ist. Ein nicht-technischer Kunde kann dies in der Regel nicht eigenständig durchführen. Ziehen Sie jemanden mit technischem Know-how hinzu (kunden-IT oder eConnect-Support).
InvoiceReceivedInvoiceSentInvoiceSentErrorInvoiceSentRetryInvoiceResponseReceivedMessageLevelStatusReceivedMessageLevelStatusSentOrderReceivedMLS (Message Level Status) ist der Nachfolger des älteren MLR und gibt der sendenden Partei Feedback über den Empfang und die Verarbeitung eines Dokuments. MLS ist nicht standardmäßig aktiviert und muss pro Party über die reviews-Capability in der SMP-Konfiguration konfiguriert werden. Sobald MLS aktiviert ist, handhabt der PSB es automatisch: als empfangender Service Provider sendet der PSB eine MLS-Nachricht an den Absender zurück nach Empfang und Zustellung.
Wenn Sie selbst Dokumente über den PSB versenden, erhalten Sie MLS-Feedback von der empfangenden Partei als Webhook-Event zum Topic MessageLevelStatusReceived. Als empfangender Service Provider folgt ein separater Webhook mit Topic MessageLevelStatusSent, sobald der PSB im Auftrag von Ihnen eine MLS an den sendenden SP verschickt. Nutzen Sie dieses Topic, um zu überwachen, ob Ihre eigenen ausgehenden MLS-Antworten korrekt zugestellt werden.
MessageLevelStatusSent ist keine Bestätigung einer versendeten Rechnung. Das Topic betrifft eine MLS, die der PSB als Reaktion auf ein empfangenes Dokument sendet (Sie als empfangender SP senden die Statusmeldung an den ursprünglichen Absender zurück), nicht eine von Ihnen selbst versendete E-Rechnung. Bei vielen MessageLevelStatusSent-Meldungen neben wenigen versendeten Rechnungen: prüfen Sie, ob der Hook auf der Wildcard *sent statt spezifisch auf InvoiceSent hört (siehe Wildcard-Topics).
Der Payload enthält unter anderem:
documentIdrefToDocumentIddetails.statusCodeAP (accepted), RE (rejected), AB (acknowledged)details.descriptionUm MLS-Nachrichten zu empfangen, muss der Peppol-Hook das Feld mlsType enthalten. Die möglichen Werte sind ALWAYS_SEND (immer MLS zurücksenden) und FAILURE_ONLY (nur bei Ablehnungen).
Tipp: Das vollständige MLS-Dokument können Sie über
GET /api/v1-beta/{partyId}/generic/{documentId}/downloadabrufen, aber der Webhook-Payload enthält in der Regel ausreichend Informationen.
Der Payload enthält immer mindestens die folgenden Felder:
topicInvoiceReceived oder InvoiceSentErrordocumentIdrefToDocumentIdMessageLevelStatusSent/MessageLevelStatusReceived ist documentId die MLS-Nachricht selbst und refToDocumentId die ursprüngliche Rechnung oder BestellungpartyIdlegalEntityId)createdBypeppol, email, network, manualUpload, ksef oder eine andere Kanalbezeichnung. Nutzen Sie dieses Feld, um die Weiterverarbeitung je Quelle zu routensentOnNeue oder unbekannte Top-Level-Felder und Erweiterungen in details können vorkommen (forward-compatible Payloads). Bauen Sie den Parser so, dass unbekannte Felder ignoriert werden, statt einen Fehler zu werfen.
Keine Rechnungsbeträge im Payload. Der Webhook-Payload enthält bewusst keine Beträge (Summe, MwSt., Positionsbeträge) und keine Rechnungspositionen. Beträge stehen im XML-Dokument selbst und sind über die Download-Endpunkte abrufbar. Das ist eine Privacy-by-Design-Entscheidung: Benachrichtigungsverkehr darf keinen finanziellen Inhalt enthalten.
Eingehende Dokumente deduplizieren Sie auf Invoice/ID + Absender-partyId + issueDate aus der abgerufenen XML-Datei. Das liegt in der Verantwortung der empfangenden Anwendung, nicht des PSB. Der PSB garantiert At-least-once-Zustellung der Benachrichtigung selbst, überwacht aber keine inhaltlichen Dubletten in einem anderen E-Rechnungs-Kanal.
Jeder Payload besteht aus den allgemeinen Feldern oben plus einem topic-spezifischen details-Block. Die folgenden Beispiele stammen aus der PSB-DevOps-Dokumentation und dienen als Referenz beim Bau oder Test eines Webhook-Consumers.
InvoiceReceived{
"topic": "InvoiceReceived",
"partyId": "NL:KVK:12345678",
"hookId": "1",
"documentId": "5618b40a-822d-4e74-8894-b489617dbaa4",
"message": "Invoice successfully received.",
"details": {
"id": "invoiceId",
"sender": "0106:87654321",
"createdBy": "peppol",
"documentTypeId": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"
},
"createdOn": "2026-04-30T09:00:00.0000000+00:00",
"sentOn": "2026-04-30T09:00:00.5000000+00:00"
}
InvoiceSent{
"topic": "InvoiceSent",
"partyId": "NL:KVK:12345678",
"hookId": "1",
"documentId": "5618b40a-822d-4e74-8894-b489617dbaa4",
"message": "Invoice successfully sent.",
"details": {
"id": "invoiceId",
"recipient": "0106:87654321",
"endpoint": "https://accp-ap.econnect.eu/as4/v1",
"protocol": "As4",
"attempt": "1",
"messageId": "3e3b336c-6563-431c-93bc-6b109dedfcc5@econnect.eu",
"sourceDocumentTypeId": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1",
"targetDocumentTypeId": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1"
},
"createdOn": "2026-04-30T09:31:57.7444125+00:00",
"sentOn": "2026-04-30T09:31:57.8703556+00:00"
}
InvoiceSentRetry und InvoiceSentError folgen derselben Struktur. Bei Retry ist attempt erhöht; bei Error beschreibt das Feld message die endgültige Fehlerursache.
MessageLevelStatusReceived{
"topic": "MessageLevelStatusReceived",
"partyId": "NL:KVK:12345678",
"hookId": "mls",
"documentId": "615a914f-4a4d-4b3a-a258-828efb2817a6",
"refToDocumentId": "d5e3bc34-96c8-4daf-b260-b7b182fa4760",
"message": "'MessageLevelStatus' received. Status: 'Accept' Description: 'Document is accepted'.",
"details": {
"statusCode": "AP",
"status": "Accept",
"description": "Document is accepted",
"documentTypeId": "urn:oasis:names:specification:ubl:schema:xsd:ApplicationResponse-2::ApplicationResponse##urn:peppol:edec:mls:1.0::2.1",
"profileId": "urn:peppol:edec:mls"
},
"createdOn": "2026-03-11T22:43:18.2766651+00:00",
"sentOn": "2026-03-11T22:43:18.8225397+00:00"
}
Interpretieren Sie details.statusCode (AP accepted, RE rejected oder AB acknowledged), details.description (Erläuterung der empfangenden Partei) und refToDocumentId (Verweis auf das ursprüngliche Dokument).
MessageLevelStatusSent{
"topic": "MessageLevelStatusSent",
"partyId": "NL:KVK:ECONNECTTS",
"hookId": "mls",
"documentId": "c4a31897-66ac-468c-a7e8-14a24f9af114",
"refToDocumentId": "be7005ff-5555-41eb-afef-f5ffec2b29ed",
"message": "'ApplicationResponse' successfully sent.",
"details": {
"statusCode": "AP",
"status": "Accept",
"description": "Document is accepted",
"profileId": "urn:peppol:edec:mls",
"sourceDocumentTypeId": "urn:oasis:names:specification:ubl:schema:xsd:ApplicationResponse-2::ApplicationResponse##urn:peppol:edec:mls:1.0::2.1",
"attempt": "1",
"protocol": "As4"
},
"createdOn": "2026-03-12T21:12:20.1621727+00:00",
"sentOn": "2026-03-12T21:12:20.3726218+00:00"
}
Für OrderSent und die übrigen Order-Topics gelten vergleichbare Strukturen mit einem topic-spezifischen details-Block. Bauen Sie einen Parser, der unbekannte Felder ignoriert: das Element details ist dynamisch und kann künftig neue Felder enthalten.
Ein Hook kann in v1-beta ein output-Array mit Regeln enthalten, die festlegen, welches Topic anhand des Aktionsergebnisses veröffentlicht wird. Damit lässt sich dynamisches Routing aufsetzen, ohne dass der aufrufende Code die Fallback-Logik selbst kennen muss.
Jede Output-Regel besteht aus zwei Feldern:
when400, 404 oder 500topic* (wie in Send*Fallback) wird zum ursprünglichen Topic expandiertDas erste passende when bestimmt das resultierende Topic. Trifft keine Regel zu oder fehlt das Feld output, fällt der Hook auf die Standard-Topics zurück.
Ein häufiges Szenario ist Peppol mit E-Mail-Fallback: ein Peppol-Hook veröffentlicht bei Zustellfehlern (HTTP 400, 404 oder 500) ein Send*Fallback-Topic, auf das ein separater Mail-Hook hört und die Rechnung per E-Mail versendet.
{
"id": "peppol",
"action": "peppol",
"name": "peppol hook",
"topics": ["Send*"],
"output": [
{ "when": "400", "topic": "Send*Fallback" },
{ "when": "404", "topic": "Send*Fallback" },
{ "when": "500", "topic": "Send*Fallback" }
],
"isActive": true
}
Wenn derselbe Mail-Hook zusätzlich explizit auf Send* hört (neben Send*Fallback), erscheint er automatisch als Kanal peppol-fallback in der queryRecipientParty-Multi-Channel-Abfrage. Der aufrufende Code kann diesen Kanal dann explizit über ?channel=peppol-fallback an den Send-Endpunkten wählen.
Conditional output topics sind nicht auf E-Mail-Fallback beschränkt. Der Mechanismus funktioniert für jede Topic-Kombination und kann zum Beispiel auch bestimmte Fehlercodes an einen SFTP-Hook oder einen externen Webhook routen.
Der PSB sichert alle Webhook-Zustellungen mit HMAC SHA256-Signaturen. Bei jeder Anfrage sendet der PSB den Header:
X-EConnect-Signature: sha256={Signatur}
Um die Signatur zu verifizieren:
X-EConnect-Signature-Header.Prüfen Sie auch das sentOn-Feld im Payload. Wenn dieser Zeitstempel älter als 5 Minuten ist, lehnen Sie die Anfrage ab. Dies verhindert Replay-Attacks, bei denen eine abgefangene Anfrage später erneut abgespielt wird.
Neben der HMAC-Verifizierung bietet der PSB zusätzliche Sicherheitsebenen:
51.144.92.226 und 13.81.124.198. Produktion: 104.40.188.59 und 104.47.148.207Wenn Sie mehrere Hooks konfiguriert haben, bestimmt der PSB den zu verwendenden Hook anhand folgender Kriterien:
&&-Klausel gewinnt beispielsweise gegen einen kürzeren Filter ohne diese Klausel. So wird eine doppelte Zustellung vermieden, ohne dass Filter sich gegenseitig ausschliessen müssen.1 < 02 < 10 < dico < peppol)Neben spezifischen Topics können Sie auch Wildcard-Patterns verwenden, um mehrere Event-Typen mit einem Hook abzufangen.
Send*Send*sent / *SentSent enden: InvoiceSent, InvoiceResponseSent, OrderSent, MessageLevelStatusSent, HookSent*ReceivedInvoiceReceived, OrderReceived, InvoiceResponseReceived usw.)Invoice*Send* ist nicht dasselbe wie *sent. Send* trifft auf Topics zu, die mit Send beginnen; dieses Pattern kommt in den Standard-PSB-Topics nicht vor. Um alle "sent"-Events abzufangen (InvoiceSent, MessageLevelStatusSent, HookSent usw.), verwenden Sie *sent. InvoiceSentRetry und InvoiceSentError enden nicht auf Sent und fallen daher nicht unter das Suffix *sent.
Statuslabels in zum Beispiel einem Daily Digest oder einer Event-Pipeline bedeuten etwas anderes als ein fehlgeschlagener Webhook-Retry (HookSentError):
Kurz: Drop-Hook vorhanden, also dropped (bewusst ignoriert, keine Dead Letter); keine passenden Hooks, also Dead Letter.
Nachfolgend sind häufige Webhook-Probleme und deren Lösungen aufgeführt.
sha256=sentOn-Feld älter als 5 MinutenHookSentError-Topic überwachen (siehe unten); fehlende Events über den Batch-Endpunkt abrufenX-EConnect-Delivery-Header (eindeutige UUID) für Deduplizierung verwendenInvoiceReceived), aber es ist kein Hook für dieses Topic registriert (nie eingerichtet oder zwischenzeitlich entfernt)InvoiceReceived in den Topics? Ohne Hook auf diesem Topic erscheint kein HookSentError — das Fehlen von Fehlermeldungen beweist also nicht, dass der Hook aktiv istMessageLevelStatusSent-E-Mails bei wenigen versendeten E-Rechnungenmailto:) oder HTTP-Webhook hört auf Wildcard *sent statt auf InvoiceSentInvoiceSent ändern (gleiche Anpassung am Mail-Hook wie am HTTP-Webhook); siehe Wildcard-TopicsInvoiceReceived-Hook)Der PSB kann eine Eingangsrechnung empfangen, ohne sie an die empfangende Partei weiterzuleiten. Das Topic InvoiceReceived bedeutet, dass der PSB die Rechnung empfangen hat; ohne Hook auf diesem Topic geht nichts an einen Endpunkt.
HookSentError existiert nur, wenn ein Hook konfiguriert ist, der nicht zustellt.Beheben Sie einen fehlenden Hook, indem Sie den bestehenden Hook aktualisieren, statt ihn zu löschen und neu zu erstellen.
Der PSB sendet Webhook-Events (z.B. InvoiceReceived bei einer eingegangenen E-Rechnung) an den konfigurierten Endpunkt. Ist dieser Endpunkt nicht erreichbar — durch ein Timeout, einen SSL-Fehler oder einen DNS-Fehler wie No such host is known — wiederholt der PSB mit exponentiellem Backoff bis zu 12 Mal, verteilt über circa 6 Tage (circa 137 Stunden, Timeout 100 Sek. pro Versuch). Bei jedem Versuch wird ein HookSentRetry-Event gesendet; nach diesen Versuchen ohne 2xx-Antwort folgt HookSentError als Abschlussstatus und der PSB stellt die Versuche ein.
Folge: Eine eingegangene E-Rechnung wird nicht an den Kunden weitergeleitet, solange der Endpunkt nicht erreichbar ist, ohne dass der Kunde dies direkt bemerkt. Empfohlene Maßnahmen:
HookSentError abonnieren, damit ein endgültiger Zustellungsfehler aktiv gemeldet wird statt unbemerkt zu bleiben. Optional auch HookSentRetry für frühzeitige Erkennung.Erste Linie: Ausfallzeit auf Kundenseite vs. technisches Problem (Akzeptanz und Produktion)
HookSentError, ein wiederholter HTTP 404 oder „Endpunkt ist offline"/„Akzeptanzumgebung ist aus" kann auch daran liegen, dass der Kunde den Akzeptanz- oder Produktionsendpunkt vorübergehend abschaltet (Entwicklung, Wartung). Das ist keine eConnect-Plattformstörung.
HookSentError, Endpunkt offline oder HTTP 404 auf dem vom Kunden konfigurierten Webhook-Endpunkt. Oft sichtbar als der exakte Text Response status code does not indicate success: 404 (Not Found) (meist eine .NET-HttpRequestException bei der ausgehenden Hook-Anfrage). Dies ist ein 404 vom Endpunkt des Kunden selbst (offline oder falscher Pfad), nicht der Peppol-Fehler PartyId not found beim Senden (SMP-404) und keine REST-Ressourcen-404 aus der Fehlerbehandlung der API.HookSentError-Runbook unten (DNS/SSL/Timeout, Logs, Monitoring, Batch-Wiederherstellung).Nehmen Sie den rohen JSON-Body des Requests, berechnen Sie den HMAC SHA256-Hash mit dem Secret, das Sie beim Erstellen des Hooks angegeben haben, und vergleichen Sie ihn mit dem Wert im Header X-EConnect-Signature (nach dem Präfix sha256=). Stimmen sie überein, wissen Sie, dass der Request vom PSB stammt und unterwegs nicht verändert wurde.
Prüfen Sie, ob sentOn nicht älter als 5 Minuten ist. Ist der Zeitstempel zu alt, weisen Sie den Request ab. So verhindern Sie Replay-Angriffe, bei denen ein zuvor abgefangener Request später erneut eingereicht wird, selbst wenn die Signatur technisch korrekt ist.
Implementieren Sie eine idempotente Verarbeitung auf Ihrer Seite, da die PSB ein Event in seltenen Fällen mehrfach zustellen kann. Geben Sie außerdem schnell einen HTTP 2xx-Status zurück: Jede andere Antwort gilt als Fehler und löst einen Retry aus. Für aufwändige Verarbeitung können Sie zuerst den Empfang bestätigen und danach über eine Queue weiterverarbeiten.
HookSentError folgt, nachdem der PSB 12 Mal (circa 6 Tage, circa 137 Stunden) ohne 2xx-Antwort versucht hat. Ein wiederholter HTTP 404 oder die Meldung, dass der Endpunkt offline ist, liegt oft daran, dass der Kunde den Akzeptanz- oder Produktionsendpunkt vorübergehend abschaltet (Entwicklung, Wartung) — das ist keine eConnect-Plattformstörung. Zunächst bestätigen, ob die Ausfallzeit beabsichtigt und vorübergehend ist; falls ja, ist bis zur Erreichbarkeit keine weitere Aktion nötig. Verpasste Events können innerhalb des Retry-Fensters von circa 6 Tagen über den Batch-Endpunkt abgerufen werden.
Dies ist erwartetes Verhalten, wenn der Mail-Hook (mailto:) oder HTTP-Webhook auf der Wildcard *sent statt spezifisch auf InvoiceSent hört. MessageLevelStatusSent ist keine Bestätigung einer selbst versendeten Rechnung, sondern einer MLS, die der PSB als Reaktion auf ein empfangenes Dokument sendet, und fällt zusammen mit InvoiceSent, OrderSent und HookSent unter das *sent-Pattern. Wenn Sie nur Benachrichtigungen beim Versenden von Rechnungen wünschen, ändern Sie die Topic-Konfiguration auf InvoiceSent. InvoiceSentRetry und InvoiceSentError enden nicht auf Sent und fallen daher nicht unter *sent.
Möchten Sie Dokumente lieber in großen Mengen abrufen? Sehen Sie sich Batch Hooks an.
Webhook-Endpoints ansehen