Webhooks
Webhooks melden Ereignisse aus einem Modul an externe Systeme. Das Modul erzeugt das Ereignis; die Runtime übernimmt dessen Zustellung. Jede Zustellung wird dauerhaft gespeichert, signiert, bei Fehlern mit wachsenden Abständen wiederholt und in Studio protokolliert.
Ereignistyp deklarieren
Deklarieren Sie Ereignisse mit [WebhookEvent] und IWebhookEvent:
[WebhookEvent("artikel.geaendert", Display = "Artikel geändert",
Description = "Feuert für jeden Artikel, den der Datenmonitor als geändert meldet.")]
public sealed record ArtikelGeaendert(
string? ArtNr,
string? Suchbegriff,
string? Bezeichnung,
string? Einheit,
double? VkPreis) : IWebhookEvent;
Das deklarierte Ereignis steht in Studio zur Auswahl für Webhook-Abonnements bereit.
Vergeben Sie einen eindeutigen Namen aus Kleinbuchstaben, Ziffern, ., _ und -.
Ereignis zustellen
Mit IWebhooks.EmitAsync senden Sie ein Ereignis an alle abonnierten Ziele:
public sealed class ArtikelWebhookModule(
IBpSession session,
IWebhooks webhooks) : BpModule
{
public override string ModuleName => "Artikel-Webhook";
public override string ModuleVersion => "1.0.0";
public override string ModuleDescription => "Sendet geänderte Artikel an abonnierte Ziele.";
[Action("artikel-webhook", Display = "Artikel-Änderungen als Webhook senden")]
[OnChanged]
public async Task<int> OnArtikelChangedAsync(ChangedSet<Artikel> changes, CancellationToken cancellationToken)
{
var queued = 0;
foreach (var artikel in changes.Items)
{
// Je geändertem Artikel ein Ereignis einreihen.
queued += await webhooks.EmitAsync(new ArtikelGeaendert(
artikel.ArtNr,
artikel.SuchBeg,
artikel.KuBez1,
artikel.Einh,
artikel.Vk0Preis), cancellationToken);
}
return queued;
}
}
EmitAsync reiht Zustellungen ein und gibt deren Anzahl zurück. Der Versand erfolgt im Hintergrund.
Payload und Header verarbeiten
{
"id": "0f8fad5bd9cb469fa165708867fc2f01",
"module": "meinefirma.artikel-webhook",
"event": "artikel.geaendert",
"timestamp": "2026-07-27T12:34:56.789Z",
"data": { "artNr": "1000", "suchbegriff": "Schraube", "vkPreis": 1.29 }
}
| Header | Bedeutung |
|---|---|
Idempotency-Key |
Bleibt über alle Wiederholungen derselben Zustellung gleich, entspricht id im Umschlag |
X-BpNexT-NET-Webhook-Id |
Identisch mit dem Idempotency-Key |
X-BpNexT-NET-Module |
Modul-ID des Absenders |
X-BpNexT-NET-Event |
Ereignisname, nur bei Abonnement-Zustellungen |
X-BpNexT-NET-Signature |
Signatur, siehe unten |
Eine 2xx-Antwort gilt als erledigt. Alles andere wird nach 1, 5, 10 und 30 Minuten sowie 1, 6, 12 und 24 Stunden erneut versucht. Die Abstände gelten jeweils ab dem vorherigen Versuch. Nach dem letzten fehlgeschlagenen Versuch werden die Administratoren benachrichtigt.
Entdoppeln Sie Wiederholungen anhand des Idempotency-Key. Ein erneuter EmitAsync-Aufruf
erzeugt hingegen einen neuen Schlüssel. Wiederholt verarbeitete Änderungsbatches benötigen
deshalb zusätzlich eine fachliche Duplikatprüfung.
Webhook-Signatur prüfen
Jeder Webhook erhält beim Anlegen ein Secret (whsec_...), das genau einmal angezeigt wird.
Damit signiert die Runtime jede Zustellung:
X-BpNexT-NET-Signature: t=1712345678,v1=5257a869e7...
t ist die Unix-Zeit des Sendeversuchs, v1 ist HMAC-SHA256(secret, "{t}.{body}") in
Hex-Darstellung. Verwenden Sie das vollständige Secret einschließlich whsec_ als UTF-8-Bytes
und den unveränderten Request-Body. Die Prüfung beim Empfänger:
signierteEingabe = t + "." + roherRequestBody
erwartet = hex(hmacSha256(secret, signierteEingabe))
gültig = timingSafeEqual(erwartet, v1) und |jetzt - t| < 5 Minuten
Die Zeitschranke verhindert das Wiedereinspielen alter Anfragen. Der Zeitstempel wird pro Sendeversuch neu gesetzt, Wiederholungen bestehen die Prüfung also ebenfalls.
Ereignis direkt an eine URL senden
SendAsync sendet einen Payload ohne Ereignisumschlag direkt an eine URL:
await webhooks.SendAsync(
zielUrl,
new { text = $"Auftrag {auftrag.Nummer} ist da." },
new WebhookSendOptions
{
SigningSecretName = "partner-webhook-secret",
Label = "partner-sync"
}, cancellationToken);
SigningSecretName benennt das Secret für die Signatur; modulspezifische Werte haben
Vorrang vor globalen. Ohne Angabe wird unsigniert gesendet. Label beschriftet die Zustellung.
Auch direkte Sendungen verwenden die Warteschlange und Wiederholungslogik.
Webhooks in Studio verwalten
Superadmins verwalten Abonnements im Paket unter Webhooks. Dort lassen sich Ziel-URL und Ereignisse auswählen, Testsendungen auslösen und Zustellversuche prüfen.
Das Secret wird nur beim Anlegen angezeigt. Geht es verloren, erstellen Sie ein neues und hinterlegen es beim Empfänger.
API-Referenz
Die API-Referenz enthält die vollständigen Webhook-Schnittstellen.