Ausgehende Webhooks
Pay4Feedback sendet HTTP-POST-Anfragen an Ihren Endpunkt, wenn Ereignisse in Ihrem Konto eintreten. Damit synchronisieren Sie Feedback in Ihr Data Warehouse, stoßen nachgelagerte Automatisierungen an oder pingen Ihre eigenen Monitoring-Systeme.
Ereignisse
| Ereignis | Auslöser |
|---|---|
feedback_submitted | Teilnehmer sendet Feedback ab und besteht das KI-Scoring |
reward_approved | Reviewer gibt die Belohnung frei (Manual-Review-Modus) |
reward_rejected | Reviewer lehnt die Belohnung ab |
payout_completed | Tremendous bestätigt die Auszahlung (oder App-Discount-Code wurde erstellt) |
campaign_activated | Kampagne wechselt nach Stripe-Zahlung von PENDING_PAYMENT auf ACTIVE |
Ein Endpunkt kann alle Ereignisse (*) abonnieren oder nur eine Auswahl.
Payload-Struktur
Alle Ereignisse teilen sich dieselbe Hülle:
{
"event": "reward_approved",
"timestamp": "2026-04-19T14:22:51Z",
"data": {
"responseId": "f3a7e1b2-...",
"rewardId": "bcd8e4f0-...",
"campaignId": "7e1c2d3a-...",
"amount": 12.50,
"currency": "EUR"
}
}
Die Felder in data variieren je Ereignis. Parsen Sie defensiv — zusätzliche Felder können ohne Versionswechsel hinzukommen.
Header
Jede Anfrage enthält:
| Header | Wert |
|---|---|
Content-Type | application/json |
User-Agent | Pay4Feedback-Webhook/1.0 |
X-Pay4Feedback-Timestamp | Unix-Sekunden zum Signierzeitpunkt |
X-Pay4Feedback-Signature | sha256=<hex> — HMAC-SHA256 über timestamp + "." + rawBody mit Ihrem Shared Secret |
Signatur prüfen
Wenn Sie beim Anlegen ein Signing-Secret hinterlegt haben, verifizieren Sie jede Lieferung, bevor Sie reagieren. Signiert wird der Timestamp, ein wörtlicher ., dann der rohe JSON-Body — ohne zusätzliche Whitespaces.
Node.js
import crypto from 'node:crypto';
function verify(req, secret) {
const ts = req.headers['x-pay4feedback-timestamp'];
const sig = req.headers['x-pay4feedback-signature']; // "sha256=abc..."
if (!ts || !sig) return false;
// Replays älter als 5 Min. verwerfen.
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(`${ts}.${req.rawBody}`) // req.rawBody muss der unparsed body sein
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
Python
import hmac, hashlib, time
def verify(timestamp: str, signature: str, raw_body: bytes, secret: str) -> bool:
if not timestamp or not signature:
return False
if abs(time.time() - int(timestamp)) > 300:
return False
expected = "sha256=" + hmac.new(
secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
PHP
function verify(string $timestamp, string $signature, string $rawBody, string $secret): bool {
if (!$timestamp || !$signature) return false;
if (abs(time() - (int)$timestamp) > 300) return false;
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);
return hash_equals($expected, $signature);
}
Parsen Sie den JSON-Body nicht neu — JSON.stringify in Node sortiert Keys um, ändert Whitespace oder Unicode-Escapes und das HMAC schlägt fehl. Fangen Sie den Raw-Body ab, bevor ein Parser ihn berührt.
Retry-Verhalten
Antwortet Ihr Endpunkt nicht innerhalb von 10 Sekunden mit 2xx (oder verbindet gar nicht), wiederholen wir mit exponentiellem Backoff:
| Versuch | Wartezeit |
|---|---|
| 1 (initial) | — |
| 2 | 1 Minute |
| 3 | 5 Minuten |
| 4 | 30 Minuten |
| 5 | 2 Stunden |
| 6 | 6 Stunden |
Nach 5 Retries wird die Zustellung als FAILED markiert und verworfen. 4xx zählt wie 5xx — beide werden retried. Antworten Sie deshalb 2xx, sobald das Ereignis dauerhaft in Ihrer Queue liegt, auch wenn die nachgelagerte Verarbeitung später fehlschlägt.
Jeder Versuch wird protokolliert. Unter Einstellungen → Webhooks → Lieferungen sehen Sie die letzten 50 Versuche pro Endpunkt: Status, HTTP-Code, Fehlermeldung, Versuchszähler. Einträge werden nach 30 Tagen gelöscht.
Best Practices
- Schnell antworten. Ereignis einfügen, 2xx zurück, dann asynchron verarbeiten. 10 s Timeout plus Transatlantik-Latenz lassen wenig Spielraum.
- Idempotent bleiben. Ein Retry kann Minuten nach dem ersten Versuch ankommen; gelingen beide, erhält Ihr Endpunkt das Ereignis zweimal. Deduplizieren Sie über
data.responseId/data.rewardId/data.claimId. - Timestamp prüfen. Verwerfen Sie Lieferungen, die älter als ein paar Minuten sind — verhindert Replay-Angriffe mit abgefangenen Payloads.
- Secret rotieren Sie, indem Sie einen zweiten Webhook mit neuem Secret anlegen, Ihren Consumer auf beide umschalten und dann den alten löschen.
Einrichtung
- Einstellungen → Webhooks → Add Endpoint.
- HTTPS-URL einfügen. Non-HTTPS-Endpunkte werden abgelehnt — Signing ersetzt keine Transportverschlüsselung.
- Signing Secret setzen. Jeder undurchsichtige String ≥ 32 Zeichen reicht; wir empfehlen kryptografisch zufällig. In Ihrem Secret Manager ablegen.
- Ereignisse auswählen — Standard ist "All events".
- Add Endpoint klicken.
- Send test auf der neuen Zeile klicken. Ein
{ "event": "test", ... }-Payload wird sofort gesendet; Response-Code bzw. Fehler erscheinen inline. Bei Nicht-2xx korrigieren und erneut testen. - Deliveries öffnen, um Live-Events mitzulesen.
Fehlersuche
"Endpoint responded with HTTP 401 / 403"
Ihr Endpunkt lehnt unauthentifizierte Requests ab, bevor die Signatur geprüft wird. Legen Sie eine Ausnahme für den Webhook-Pfad an oder verifizieren Sie die Signatur statt Bearer-Token-Auth.
"Endpoint responded with HTTP 308"
Redirects werden nicht gefolgt. Tragen Sie die finale URL direkt ein (mit/ohne www., passender TLS-Host, keine Slash-Unterschiede).
Signatur-Mismatch auf Ihrer Seite
In 99 % der Fälle: Sie haben den JSON neu serialisiert. Raw-Body fangen. In Express: app.use(express.json({ verify: (req, _, buf) => { req.rawBody = buf.toString(); } })).
Deliveries zeigt SUCCESS, aber Ihr Downstream sieht nichts
Sie haben 2xx geantwortet, bevor Ihre eigene Queue das Ereignis aufgenommen hat. Prüfen Sie die Lücke zwischen 2xx und den Verarbeitungs-Logs.
Ich brauche ein Ereignis, das nicht gelistet ist
Mail an sales@pay4feedback.com mit dem Use Case. Für konkrete Integrationen haben wir schon Ereignisse ergänzt.
Verwandt
- Slack-Benachrichtigungen — wenn ein Mensch gepingt werden soll, nicht ein System
- Microsoft-Teams-Benachrichtigungen — dasselbe für Teams-Welten
- API & Integrationen — Roadmap der öffentlichen REST-API