Skip to content
Sprache: Deutsch

API für Entwickler

Webhooks: Events, Payload und Signatur

Aktualisiert am 1. November 2026 6 Min. Lesezeit

Webhooks im Dashboard einrichten, Zustellungen empfangen und die HMAC-Signatur prüfen – mit Beispielen für curl, Node.js und PHP.

Ein Webhook schickt eine HTTP-Anfrage an deinen Server, sobald in deinem Workspace etwas passiert – zum Beispiel wenn eine Page veröffentlicht wird. So musst du nicht ständig nachfragen, ob sich etwas geändert hat. Jede Zustellung ist signiert, damit dein Server echte Nachrichten von gefälschten unterscheiden kann.

Voraussetzungen

  • Eigentümer oder Admin im Workspace – der Menüpunkt „Webhooks“ erscheint nur für diese Rollen
  • Ab Creator Pro; in Creator Free steht dort „Webhooks sind ab Creator Pro verfügbar.“
  • Bis zu 5 Webhooks in Creator Pro, 25 in Creator Agency, 100 in Enterprise (anpassbar)
  • Ein Server, der unter einer öffentlichen https-Adresse erreichbar ist

Webhooks verwaltest du ausschließlich im Dashboard. Mit API-Keys lassen sie sich nicht anlegen oder ändern.

Webhook anlegen

Webhooks-Seite ohne Webhooks mit dem Button „+ Neuer Webhook“
Die Webhooks-Seite im Workspace
  1. Öffne in der Navigation „Webhooks“
  2. Klicke auf „+ Neuer Webhook“
  3. Trag die Ziel-URL ein und wähle die Events
  4. Optional: Beschreibung eintragen und Status wählen
  5. Klicke auf „Webhook erstellen“
  6. Kopiere im Schritt „Fertig“ das Signing-Secret („Signing-Secret – nur jetzt sichtbar“) und hinterlege es auf deinem Server – es wird nur jetzt angezeigt
  7. Teste den Webhook mit „Test“. Das Ergebnis bleibt bis zum nächsten Test an der Karte stehen: „Erfolgreich zugestellt“ oder „Nicht zugestellt“ mit HTTP-Code (oder „keine Antwort“), Dauer und dem Anfang der Antwort
„Ziel-URL (https://…)“
Bis zu 2048 Zeichen. Nur https, keine Zugangsdaten in der URL, keine localhost-Adressen und keine internen Namen wie .local, .internal oder .lan. Der Name muss auf öffentliche IP-Adressen zeigen; das prüft LinkHarbor vor jeder Zustellung erneut.
„Events“
Mindestens ein Event. Pro Gruppe gibt es „Alle auswählen“ und „Alle abwählen“.
„Beschreibung“
Optional, bis zu 255 Zeichen – zum Beispiel, wofür der Webhook gedacht ist.
„Status“
„Aktiv“ oder „Deaktiviert“. Deaktivierte Webhooks bekommen keine Zustellungen.

Events

EventIm DashboardWannInhalt von data
page.publishedPage veröffentlichtEine Page wurde veröffentlicht – im Dashboard, per API oder per KI-Assistentpage_id, version, checksum, published_by_user_id (bei API-Keys und KI-Assistenten null)
form.submittedFormular abgeschicktEin Besucher hat ein Formular auf einer deiner Pages abgeschicktform_id, form_name, submission_id, page_id, block_id, submitted_at, values (Feld-Key → Wert), consent (Einwilligungs-Key → true/false)
domain.verifiedDomain verifiziertEine eigene Domain wurde erfolgreich geprüftdomain_id, hostname, verification_method, status
domain.disabledDomain deaktiviertEine eigene Domain wurde im Dashboard deaktiviert (nicht bei einem Downgrade)domain_id, hostname, status
webhook.test– (Button „Test“)Du klickst auf „Test“message (Hinweistext in der Kontosprache der Person, die den Test auslöst; nicht darauf prüfen)

form.submitted enthält die Werte genau so, wie der Besucher sie abgeschickt hat, aber nie seine IP-Adresse oder seinen Browser. Die Zustellung läuft im Hintergrund: Der Besucher wartet nicht darauf, und eine fehlgeschlagene Zustellung verhindert die Einsendung nicht.

Aufbau einer Zustellung

LinkHarbor schickt jede Zustellung als POST mit JSON-Body und diesen Headern:

HeaderInhalt
Content-Typeapplication/json
X-LinkHarbor-EventName des Events, zum Beispiel page.published
X-LinkHarbor-Delivery-IdEindeutige ID dieser Zustellung (UUID), identisch mit id im Body
X-LinkHarbor-TimestampZeitpunkt des Versands in Unix-Sekunden
X-LinkHarbor-Signaturesha256= gefolgt von der HMAC-SHA256-Signatur in Hex
X-LinkHarbor-Signature-Versionv1
Beispiel-Payload page.published
{
  "id": "3f1c2a9e-8d4b-4a51-9f0e-6b7c1d2e3f40",
  "event": "page.published",
  "created_at": "2026-11-01T09:30:12+00:00",
  "data": {
    "page_id": 42,
    "version": 8,
    "checksum": "9b1e5c…",
    "published_by_user_id": 7
  }
}

Erneute Zustellungen bekommen eine neue id und zusätzlich die Felder redelivery_of (die ID der wiederholten Zustellung) und delivery_root (die ID der ersten Zustellung dieser Kette).

Signatur prüfen

Jeder Webhook hat ein eigenes Signing-Secret (32 Hex-Zeichen). Du siehst es genau einmal: im letzten Schritt beim Anlegen und direkt nach „Secret ↺“. Kopiere es dann sofort auf deinen Server – LinkHarbor zeigt es später nicht noch einmal. Damit berechnet LinkHarbor die Signatur so:

  1. Nachricht bilden: Timestamp, Punkt, Delivery-ID, Punkt, roher Body – also timestamp.delivery_id.body
  2. HMAC-SHA256 über diese Nachricht mit dem Signing-Secret als Schlüssel berechnen
  3. Ergebnis als Hex-Zeichenkette mit dem Präfix sha256= senden

Dein Server sollte die Signatur mit einem zeitkonstanten Vergleich prüfen, Zustellungen mit einem Timestamp älter als 300 Sekunden ablehnen und die Delivery-IDs mindestens so lange speichern, um Wiederholungen zu erkennen. Wichtig: Signiert wird der rohe Body, genau so, wie er ankommt – nicht ein neu erzeugtes JSON.

Node.js (Express): Webhook empfangen und prüfen
import crypto from 'node:crypto';
import express from 'express';

const app = express();
const SECRET = process.env.LH_WEBHOOK_SECRET;
const seen = new Set(); // in Produktion: Datenbank oder Redis mit Ablaufzeit

app.post('/webhooks/linkharbor', express.raw({ type: 'application/json' }), (req, res) => {
  const ts = req.get('X-LinkHarbor-Timestamp') || '';
  const id = req.get('X-LinkHarbor-Delivery-Id') || '';
  const sig = req.get('X-LinkHarbor-Signature') || '';

  if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) {
    return res.status(400).send('timestamp');
  }

  const expected = 'sha256=' + crypto
    .createHmac('sha256', SECRET)
    .update(ts + '.' + id + '.')
    .update(req.body) // roher Body als Buffer
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(sig);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('signature');
  }

  const event = JSON.parse(req.body.toString('utf8'));
  const key = event.delivery_root || event.id; // Wiederholungen derselben Kette erkennen
  if (!seen.has(key)) {
    seen.add(key);
    // hier verarbeiten, am besten asynchron in einer Queue
  }
  res.sendStatus(200);
});

app.listen(3000);
PHP: Webhook empfangen und prüfen
<?php
$secret = getenv('LH_WEBHOOK_SECRET');
$body   = file_get_contents('php://input');
$ts     = $_SERVER['HTTP_X_LINKHARBOR_TIMESTAMP'] ?? '';
$id     = $_SERVER['HTTP_X_LINKHARBOR_DELIVERY_ID'] ?? '';
$sig    = $_SERVER['HTTP_X_LINKHARBOR_SIGNATURE'] ?? '';

if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
    http_response_code(400);
    exit('timestamp');
}

$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $id . '.' . $body, $secret);
if (!hash_equals($expected, $sig)) {
    http_response_code(401);
    exit('signature');
}

$event = json_decode($body, true);
// Doppelte Zustellungen anhand von $event['delivery_root'] ?? $event['id'] erkennen,
// dann verarbeiten.
http_response_code(200);

Deinen Endpunkt mit curl testen

Mit diesem Skript schickst du eine korrekt signierte Test-Zustellung an deinen eigenen Server – praktisch, bevor du den Webhook in LinkHarbor anlegst:

Signierte Test-Zustellung simulieren
SECRET="dein-signing-secret"
URL="https://example.com/webhooks/linkharbor"
TS=$(date +%s)
ID=$(uuidgen | tr 'A-Z' 'a-z')
BODY='{"id":"'"$ID"'","event":"webhook.test","created_at":"2026-11-01T09:30:12+00:00","data":{"message":"Das ist ein Test-Event für diesen Webhook."}}'
SIG="sha256=$(printf '%s' "$TS.$ID.$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')"

curl -X POST "$URL" \
  -H "Content-Type: application/json" \
  -H "X-LinkHarbor-Event: webhook.test" \
  -H "X-LinkHarbor-Delivery-Id: $ID" \
  -H "X-LinkHarbor-Timestamp: $TS" \
  -H "X-LinkHarbor-Signature: $SIG" \
  -H "X-LinkHarbor-Signature-Version: v1" \
  -d "$BODY"

Antwort, Timeout und erneute Zustellung

  • Jede Antwort mit einem 2xx-Status gilt als Erfolg; Weiterleitungen (3xx) werden nicht verfolgt
  • Dein Server hat 10 Sekunden Zeit für die Antwort, der Verbindungsaufbau höchstens 5 Sekunden
  • Alle Webhooks eines Events teilen sich zusammen 25 Sekunden; wer danach noch nicht dran war, wird als fehlgeschlagen vermerkt und kann erneut zugestellt werden
  • LinkHarbor wiederholt fehlgeschlagene Zustellungen nicht automatisch
  • Fehlgeschlagene Zustellungen kannst du von Hand erneut senden, eine inzwischen erfolgreiche nicht. Die erneute Zustellung hat eine neue id und ein neues created_at
  • Pro Ereignis sind höchstens 3 Versuche erlaubt, die erste Zustellung mitgezählt; danach landet es unter „Dead Letters“ und lässt sich nicht mehr erneut senden

Zustellungen im Dashboard

Mit „Zustellungen“ öffnest du das Protokoll eines Webhooks. Es hat drei Tabs:

„Alle Zustellungen“
Alle Zustellungen mit Filter nach Event, Status („Erfolg (2xx)“, „Client-Fehler (4xx)“, „Server-Fehler (5xx)“, „Fehlgeschlagen“) und „Limit“. „↺ Erneut“ stellt eine fehlgeschlagene Zustellung noch einmal zu, solange es keine spätere erfolgreiche gibt. Ein Klick auf eine Zeile zeigt Request, Response, Body und das rohe JSON.
„Replays“
Ketten von erneuten Zustellungen mit dem Ergebnis „Wiederhergestellt“ oder „Weiterhin fehlgeschlagen“ und der Zahl der Versuche.
„Dead Letters“
Zustellungen, bei denen alle erlaubten Versuche fehlgeschlagen sind – die erste Zustellung und die erneuten zusammen. Der Tab ist nur zum Ansehen: Erneut zustellen lassen sie sich nicht mehr. Prüfe deinen Endpunkt; neue Ereignisse werden danach wieder normal zugestellt. Brauchst du die Daten, hol sie über die API nach.

Klappt eine erneute Zustellung nicht, nennt das Dashboard den Grund:

„Nicht erneut zugestellt: Dieses Ereignis wurde schon …-mal ohne Erfolg zugestellt, mehr Versuche sind nicht möglich. Du findest es unter „Dead Letters“.“
Alle 3 Versuche sind verbraucht.
„Nicht erneut zugestellt: Dieses Ereignis wurde inzwischen erfolgreich zugestellt.“
Eine spätere Zustellung derselben Kette hat schon geklappt.

Verifikation im Dashboard

Unter „Verifikation“ findest du zwei Hilfen:

„Verification Kit“
„Kit laden“ zeigt Algorithmus, Header-Namen, das Format der signierten Nachricht und die empfohlene Toleranz von 300 Sekunden. Das Secret selbst ist nicht enthalten.
„Signatur prüfen“
Trag Delivery-ID, Timestamp, Signatur und den rohen Request-Body einer empfangenen Zustellung ein. LinkHarbor sagt dir dann „Signatur gültig“ oder „Signatur ungültig“. Timestamp und Signatur kopierst du aus den Headern X-LinkHarbor-Timestamp und X-LinkHarbor-Signature. Die Prüfung gilt nur für Zustellungen der letzten 5 Minuten; bei älteren meldet sie „Signatur ungültig“, auch wenn die Signatur stimmt.

Secret rotieren, deaktivieren, löschen

  • „Secret ↺“ erzeugt ein neues Signing-Secret und zeigt es einmal an; das alte gilt ab sofort nicht mehr, und dein Server muss das neue verwenden
  • Über „Bearbeiten“ setzt du den Status auf „Deaktiviert“, um Zustellungen zu pausieren
  • Das Papierkorb-Symbol löscht den Webhook; bis du die Meldung schließt, kannst du mit „Rückgängig“ abbrechen

Beim Wechsel auf einen kleineren Plan werden Webhooks über dem neuen Limit deaktiviert, in Creator Free alle. Sie bleiben erhalten; nach einem Upgrade schaltet LinkHarbor deaktivierte Webhooks automatisch wieder ein, bis zum Limit des neuen Plans – auch solche, die du selbst deaktiviert hattest.

Nichts gefunden?

Schreib uns dein Anliegen – unser Support hilft dir persönlich weiter.

Support kontaktieren