Zum Hauptinhalt springen

Webhooks

Selgeo sendet Echtzeit-HTTP-POST-Benachrichtigungen an Ihren Server, wenn Ereignisse in Ihrem Konto auftreten. Verwenden Sie Webhooks, um Workflows zu automatisieren, wie z. B. den Zugriff zu gewähren, wenn ein Partner genehmigt wird, Provisionen mit Ihrem Buchhaltungssystem zu synchronisieren oder Ihr Team über Betrug zu benachrichtigen.

Alle Webhook-Payloads verwenden API-Version v1.

Endpunkt-Registrierung

Registrieren Sie Webhook-Endpunkte auf der Seite Einstellungen > Webhooks im Händler-Dashboard.

  1. Klicken Sie auf Endpunkt hinzufügen.
  2. Geben Sie die URL ein, unter der Sie Ereignisse empfangen möchten. Live-Modus-Endpunkte müssen HTTPS verwenden. Test-Modus-Endpunkte dürfen HTTP für die lokale Entwicklung verwenden.
  3. Wählen Sie die Ereignisse aus, die Sie abonnieren möchten.
  4. Klicken Sie auf Erstellen. Ihr Signierungsgeheimnis (whsec_...) wird einmal angezeigt – kopieren Sie es und speichern Sie es sicher.

Sie können bis zu 10 Endpunkte pro Modus (Test und Live separat) registrieren.

Test-Pings

Verwenden Sie nach der Erstellung eines Endpunkts die Schaltfläche Test-Ping senden, um die Konnektivität zu überprüfen. Der Ping sendet ein webhook.test-Ereignis an Ihre URL und meldet den HTTP-Statuscode.

Geheimnisse rotieren

Wenn Ihr Signierungsgeheimnis kompromittiert ist, verwenden Sie die Aktion Geheimnis rotieren am Endpunkt. Dadurch wird sofort ein neues Geheimnis generiert – das alte funktioniert nicht mehr. Aktualisieren Sie Ihren Verifizierungscode, bevor Sie rotieren.

Signaturverifizierung

Jede Webhook-Anfrage enthält einen X-Selgeo-Signature-Header im Format:

t=<unix_timestamp>,v1=<hmac_hex>

Der HMAC wird berechnet als HMAC-SHA256(signing_secret_bytes, "<timestamp>.<raw_json_body>"). Das Signierungsgeheimnis hat ein whsec_-Präfix, gefolgt von 64 Hex-Zeichen. Entfernen Sie das Präfix und hex-dekodieren Sie, um den 32-Byte-Schlüssel zu erhalten.

Überprüfen Sie immer die Signatur, bevor Sie die Payload verarbeiten. Dies schützt vor gefälschten Anfragen.

Verifizierungsbeispiele

import crypto from 'node:crypto';

function verifyWebhookSignature(signingSecret, signatureHeader, rawBody) {
if (!signatureHeader) {
return false;
}

// whsec_-Präfix entfernen und hex-dekodieren, um rohe Schlüssel-Bytes zu erhalten
const rawSecret = signingSecret.replace(/^whsec_/, '');
const secretBytes = Buffer.from(rawSecret, 'hex');

// Header parsen: t=<ts>,v1=<hmac>
const parts = Object.fromEntries(
signatureHeader.split(',').map((part) => {
return part.split('=', 2);
})
);

const timestamp = parts.t;
const receivedHmac = parts.v1;

if (!timestamp || !receivedHmac) {
return false;
}

// Zeitstempel ablehnen, die älter als 5 Minuten oder in der Zukunft sind (mit 30s Toleranz)
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (age > 300 || age < -30) {
return false;
}

// Den erwarteten HMAC berechnen
const expectedHmac = crypto
.createHmac('sha256', secretBytes)
.update(`${timestamp}.${rawBody}`)
.digest('hex');

// Zeitkonstanter Vergleich (Buffer müssen gleiche Länge haben)
const receivedBuf = Buffer.from(receivedHmac, 'hex');
const expectedBuf = Buffer.from(expectedHmac, 'hex');
if (receivedBuf.length !== expectedBuf.length) {
return false;
}
return crypto.timingSafeEqual(receivedBuf, expectedBuf);
}

// Verwendung in einem Express-Handler
app.post('/webhooks/selgeo', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-selgeo-signature'];
const rawBody = req.body.toString();

if (!verifyWebhookSignature('whsec_YOUR_SIGNING_SECRET', signature, rawBody)) {
return res.status(401).send('Invalid signature');
}

const event = JSON.parse(rawBody);
console.log('Ereignis empfangen:', event.event_name);

// Ereignis verarbeiten...

res.status(200).send('OK');
});
tipp

Verwenden Sie immer den rohen Anfragekörper-String für die Signaturverifizierung, nicht eine re-serialisierte Version des geparsten JSON. Re-Serialisierung kann die Schlüsselreihenfolge oder Leerzeichen ändern, was den HMAC ungültig macht.

Ereigniskatalog

Jede Webhook-Payload enthält diese Envelope-Felder:

FeldTypBeschreibung
event_idstringEindeutige ID für dieses Ereignis (nanoid, 21 Zeichen)
delivery_idstringEindeutige ID für diesen Zustellungsversuch
event_namestringEreignistyp (siehe Tabelle unten)
occurred_atstringISO 8601 Zeitstempel
merchant_idstringIhre Händlerkonto-ID
mode"test" | "live"Ob dieses Ereignis im Test- oder Live-Modus aufgetreten ist
api_version"v1"API-Version

Partner-Ereignisse

EreignisBeschreibung
participant.createdEin neuer Partner hat sich beworben oder wurde einem Programm hinzugefügt
participant.approvedEin Partner wurde genehmigt (manuell oder durch Auto-Genehmigung)
participant.rejectedEine Partner-Bewerbung wurde abgelehnt
participant.suspendedEin aktiver Partner wurde gesperrt
participant.reinstatedEin gesperrter Partner wurde wiederhergestellt
participant.erasedDie Daten eines Partners wurden gelöscht (DSGVO)
participant.data_exportedDie Daten eines Partners wurden exportiert (DSGVO)
Beispiel: participant.approved
{
"event_id": "evt_abc123def456ghi78",
"delivery_id": "dlv_xyz789abc012def34",
"event_name": "participant.approved",
"occurred_at": "2026-03-15T10:30:00.000Z",
"merchant_id": "mch_your_merchant_id",
"mode": "live",
"api_version": "v1",
"participant_id": "prt_partner_id",
"program_id": "prg_program_id",
"approved_at": "2026-03-15T10:30:00.000Z"
}

Attributionsereignisse

EreignisBeschreibung
attribution.createdEin Klick wurde einem Partner zugeordnet
attribution.convertedEin zugeordneter Klick führte zu einer Konversion
attribution.expiredEin Attributionsfenster ist ohne Konversion abgelaufen
attribution.duplicate_detectedEine doppelte Attribution wurde erkannt

Konversionsereignisse

EreignisBeschreibung
conversion.createdEine neue Konversion wurde aufgezeichnet
conversion.fraud_detectedBetrug wurde erkannt (Selbst-Empfehlung oder doppelte Konversion)
Beispiel: conversion.created
{
"event_id": "evt_abc123def456ghi78",
"delivery_id": "dlv_xyz789abc012def34",
"event_name": "conversion.created",
"occurred_at": "2026-03-15T14:22:00.000Z",
"merchant_id": "mch_your_merchant_id",
"mode": "live",
"api_version": "v1",
"conversion_id": "cnv_conversion_id",
"attribution_id": "att_attribution_id",
"participant_id": "prt_partner_id",
"program_id": "prg_program_id",
"amount_cents": 9900,
"currency": "EUR",
"conversion_scope": "first_conversion",
"created_at": "2026-03-15T14:22:00.000Z"
}
Beispiel: conversion.fraud_detected
{
"event_id": "evt_abc123def456ghi78",
"delivery_id": "dlv_xyz789abc012def34",
"event_name": "conversion.fraud_detected",
"occurred_at": "2026-03-15T14:25:00.000Z",
"merchant_id": "mch_your_merchant_id",
"mode": "live",
"api_version": "v1",
"fraud_type": "self_referral",
"program_id": "prg_program_id",
"program_name": "My SaaS Affiliates",
"participant_id": "prt_partner_id",
"attribution_event_id": "att_attribution_id",
"conversion_id": null,
"external_transaction_id": "cs_live_abc123",
"masked_context": "us***@example.com",
"explanation": "Customer email matches partner email after RFC 5233 normalization",
"detected_at": "2026-03-15T14:25:00.000Z"
}

Provisionsereignisse

EreignisBeschreibung
commission.createdEine neue Provision wurde berechnet
commission.approvedEine Provision wurde für die Auszahlung genehmigt
commission.rejectedEine Provision wurde abgelehnt
commission.paidEine Provision wurde in eine Auszahlung einbezogen (demnächst verfügbar)
commission.refundedEine Provision wurde aufgrund einer Rückerstattung storniert
Beispiel: commission.created
{
"event_id": "evt_abc123def456ghi78",
"delivery_id": "dlv_xyz789abc012def34",
"event_name": "commission.created",
"occurred_at": "2026-03-15T14:22:05.000Z",
"merchant_id": "mch_your_merchant_id",
"mode": "live",
"api_version": "v1",
"commission_id": "cms_commission_id",
"conversion_id": "cnv_conversion_id",
"participant_id": "prt_partner_id",
"program_id": "prg_program_id",
"amount_cents": 1980,
"currency": "EUR",
"commission_type": "percentage",
"commission_rate": 20,
"needs_review": false,
"created_at": "2026-03-15T14:22:05.000Z"
}

Auszahlungsereignisse (demnächst verfügbar)

Auszahlungsereignisse werden verfügbar sein, wenn die Auszahlungsverarbeitungsfunktion startet.

EreignisBeschreibung
payout.createdEin Auszahlungs-Batch wurde erstellt
payout.initiatedEine Auszahlungsüberweisung wurde initiiert
payout.paidEine Auszahlung wurde erfolgreich überwiesen
payout.failedEine Auszahlungsüberweisung ist fehlgeschlagen
payout.retriedEine fehlgeschlagene Auszahlung wurde wiederholt
payout.cancelledEine Auszahlung wurde storniert

Tracking-Ereignisse

EreignisBeschreibung
tracking_identifier.createdEin neuer Tracking-Link wurde für einen Partner erstellt

Promo-Code-Ereignisse

EreignisBeschreibung
promo_code.createdEin Promo-Code wurde erstellt
promo_code.stripe_syncedEin Promo-Code wurde mit Stripe synchronisiert
promo_code.deactivatedEin Promo-Code wurde deaktiviert

Programm-Einladungsereignisse

EreignisBeschreibung
program_invite.createdEine Einladung wurde erstellt
program_invite.acceptedEine Einladung wurde von einem Partner angenommen
program_invite.revokedEine Einladung wurde widerrufen
program_invite.expiredEine Einladung ist abgelaufen

Wiederholungsrichtlinie

Wenn Ihr Endpunkt einen Nicht-2xx-Statuscode zurückgibt oder die Anfrage eine Zeitüberschreitung hat (30 Sekunden), wiederholt Selgeo mit exponentiellem Backoff:

VersuchVerzögerung nach Fehler
1. Wiederholung1 Minute
2. Wiederholung2 Minuten
3. Wiederholung4 Minuten
4. Wiederholung15 Minuten

Nach 5 Gesamtversuchen (1 initial + 4 Wiederholungen) wechselt die Zustellung in den Dead-Letter-Status. Dead-Letter-Zustellungen sind im Händler-Dashboard unter dem Zustellungslog des Endpunkts sichtbar, werden aber nicht automatisch wiederholt.

Zustellungsstatus

StatusBedeutung
pendingFür die Zustellung eingereiht
deliveredIhr Endpunkt hat 2xx zurückgegeben
failedZustellung fehlgeschlagen, Wiederholung geplant
dead_letterAlle Wiederholungsversuche erschöpft

Best Practices

  • Schnell 200 zurückgeben. Bestätigen Sie den Empfang mit einem 200-Statuscode, sobald Sie den Webhook erhalten. Verarbeiten Sie das Ereignis asynchron in einem Hintergrundauftrag. Selgeo hat eine Zeitüberschreitung nach 30 Sekunden.
  • Duplikate behandeln. Verwenden Sie das event_id-Feld zur Deduplizierung. Dasselbe Ereignis kann in seltenen Fällen mehr als einmal zugestellt werden (z. B. Netzwerkzeitüberschreitung direkt nachdem Ihr Server es verarbeitet hat).
  • Signaturen verifizieren. Überprüfen Sie immer den X-Selgeo-Signature-Header. Verarbeiten Sie niemals unverifizierte Payloads.
  • Zeitstempel prüfen. Lehnen Sie Signaturen mit Zeitstempeln ab, die älter als 5 Minuten sind oder zu weit in der Zukunft liegen, um Replay-Angriffe zu verhindern.
  • HTTPS in der Produktion verwenden. Live-Modus-Endpunkte erfordern HTTPS. Test-Modus-Endpunkte erlauben HTTP für die lokale Entwicklung.
  • Dead-Letter-Zustellungen überwachen. Prüfen Sie das Zustellungslog im Dashboard regelmäßig. Dead-Letter-Ereignisse können auf einen Endpunktausfall oder einen Fehler in Ihrem Handler hinweisen.