Webhooks
Empfange signierte, wiederholte Events, statt auf das Ende von Hintergrundjobs zu warten.
Events
Abonniere einen Endpunkt für beliebige dieser Events:
| Event | Wird ausgelöst, wenn |
|---|---|
post.published | ein Post erfolgreich auf LinkedIn veröffentlicht wurde. |
post.publish_failed | das Veröffentlichen endgültig fehlgeschlagen ist (nach Wiederholungen). |
post.images_ready | die Bildvorschläge für einen Post fertig erzeugt sind. |
idea.created | eine neue Content-Idee erstellt wurde. |
Endpunkt registrieren
Das secret wird beim Erstellen einmalig zurückgegeben. Bewahre es auf — damit wird jede Zustellung geprüft, und es wird nie wieder angezeigt.
curl -X POST https://app.tidefall.de/api/v1/webhooks \
-H "Authorization: Bearer lps_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example.com/hooks/lps",
"events": ["post.published", "post.publish_failed"]
}'{
"endpoint": {
"id": "f3a1...",
"url": "https://your-app.example.com/hooks/lps",
"events": ["post.published", "post.publish_failed"],
"is_active": true,
"created_at": "2026-06-16T08:00:00Z"
},
"secret": "whsec_..."
}Zustellformat
Jede Zustellung ist ein HTTP-POST mit JSON-Body und diesen Headern:
X-LPS-Event— der Event-Name, z. B.post.published.X-LPS-Delivery-Id— eine eindeutige ID für diesen Zustellversuch.X-LPS-Signature—sha256=<hmac(secret, rawBody)>.
{
"event": "post.published",
"data": {
"post_id": "9b1c...",
"linkedin_url": "https://www.linkedin.com/feed/update/urn:li:share:...",
"published_at": "2026-06-16T09:00:00Z"
}
}Signatur prüfen
Berechne den HMAC-SHA256 des rohen Request-Bodys mit dem Secret deines Endpunkts und vergleiche ihn mit X-LPS-Signature in konstanter Zeit. Weise jede Anfrage ab, die nicht übereinstimmt.
import crypto from "node:crypto";
function verify(rawBody: string, header: string, secret: string): boolean {
const expected =
"sha256=" +
crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(header);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// In your handler — verify against the RAW body, before JSON.parse:
const raw = await req.text();
if (!verify(raw, req.headers.get("x-lps-signature") ?? "", SECRET)) {
return new Response("invalid signature", { status: 401 });
}
const event = JSON.parse(raw);Wiederholungen
Bestätige mit einem beliebigen 2xx-Status. Eine Nicht-2xx-Antwort oder ein Timeout wird mit exponentiellem Backoff wiederholt (bis zu 5 Versuche). Mach deinen Handler idempotent — dedupliziere über X-LPS-Delivery-Id, da dasselbe Event mehrfach zugestellt werden kann.
Sieh dir die letzten Versuche (Status, Antwortcode, letzter Fehler) zur Fehlersuche an:
curl https://app.tidefall.de/api/v1/webhooks/f3a1.../deliveries \
-H "Authorization: Bearer lps_YOUR_KEY"