← Entwickler

Webhooks

Empfange signierte, wiederholte Events, statt auf das Ende von Hintergrundjobs zu warten.

Events

Abonniere einen Endpunkt für beliebige dieser Events:

EventWird ausgelöst, wenn
post.publishedein Post erfolgreich auf LinkedIn veröffentlicht wurde.
post.publish_faileddas Veröffentlichen endgültig fehlgeschlagen ist (nach Wiederholungen).
post.images_readydie Bildvorschläge für einen Post fertig erzeugt sind.
idea.createdeine 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"