FastComments.com

Webhooks

Mit FastComments ist es möglich, einen API-Endpunkt aufzurufen, wann immer ein Kommentar in unserem System hinzugefügt, aktualisiert oder entfernt wird.

Wir realisieren dies mit asynchronen Webhooks über HTTP/HTTPS.

Was sind Webhooks Internal Link

Ein Webhook ist ein Mechanismus oder eine Integration zwischen zwei Systemen, bei dem der "Produzent" (FastComments) ein Ereignis auslöst das der "Konsument" (Sie) per API-Aufruf verarbeitet.

Unterstützte Ereignisse & Ressourcen Internal Link

FastComments unterstützt Webhooks nur für die Comment‑Ressource.

Wir unterstützen Webhooks für das Erstellen, Entfernen und Aktualisieren von Kommentaren.

Jedes dieser Ereignisse wird in unserem System als separates Event betrachtet und hat daher unterschiedliche Semantiken und Strukturen für die Webhook‑Events.

Eine beliebige Anzahl von Endpunkten kann dasselbe Event abonnieren, über das Dashboard oder über die API (siehe Verwalten von Webhooks über die API). Jeder Webhook wird unabhängig zugestellt.

Testen Internal Link

Die neuen Webhook-Seiten zum Erstellen und Bearbeiten haben eine Send Test Payload-Schaltfläche, die eine Anfrage an die aktuell im Formular befindliche URL sendet, unabhängig davon, ob sie gespeichert wurde oder nicht. Die Create- und Update-Events senden ein Dummy-WebhookComment-Objekt, während beim Testen von Delete ein Dummy-Request-Body mit nur einer ID gesendet wird.

Verifizierung von Payloads

Beim Testen Ihrer Webhook-Integration sollten Sie überprüfen, ob die eingehenden Anfragen die folgenden Header enthalten:

  1. X-FastComments-Timestamp - Unix-Zeitstempel (Sekunden)
  2. X-FastComments-Signature - HMAC-SHA256-Signatur

Webhooks, die vor Einführung des Signaturschemas erstellt wurden, erhalten außerdem einen token-Header, der Ihr API-Secret enthält. Neue Webhooks nicht.

Verwenden Sie die HMAC-Signaturverifizierung, um sicherzustellen, dass die Payloads authentisch sind.

Test-Tools

Sie können Tools wie webhook.site oder ngrok verwenden, um eingehende Webhook-Payloads während der Entwicklung zu inspizieren.

Event-Typen

  • Create-Event: Wird ausgelöst, wenn ein neuer Kommentar erstellt wird.
  • Update-Event: Wird ausgelöst, wenn ein Kommentar bearbeitet wird.
  • Delete-Event: Wird ausgelöst, wenn ein Kommentar gelöscht wird.

Jeder Webhook ist an ein Event und eine HTTP-Methode (POST, PUT oder DELETE) gebunden. Jedes Event enthält die vollständigen Kommentardaten im Request-Body (siehe Datenstrukturen für das Payload-Format).

Datenstrukturen Internal Link

Die einzige Struktur, die über Webhooks gesendet wird, ist das WebhookComment-Objekt, das unten in TypeScript dargestellt ist.

Die Struktur des WebhookComment-Objekts

Die Struktur des „Create“-Ereignisses

Der Request-Body des „create“-Ereignisses ist ein WebhookComment-Objekt.

Die Struktur des „Update“-Ereignisses

Der Request-Body des „update“-Ereignisses ist ein WebhookComment-Objekt.

Die Struktur des „Delete“-Ereignisses

Der Request-Body des „delete“-Ereignisses ist ein WebhookComment-Objekt.

Änderung vom 14. November 2023
Zuvor enthielt der Request-Body des „delete“-Ereignisses nur die Kommentar-ID. Er enthält jetzt den vollständigen Kommentar zum Zeitpunkt der Löschung.

Jeder Schlüssel ist im Body immer vorhanden. Wenn der Kommentar für ein Feld keinen Wert hat, trägt der Body null (oder false für Booleans und [] für Listen), sodass die Form einer Zustellung von Kommentar zu Kommentar nie variiert.

Das WebhookComment-Objekt
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** Die ID des Kommentars. **/
4 id: string
5 /** Die ID oder URL, die den Kommentar-Thread identifiziert. Normalisiert. **/
6 urlId: string
7 /** Die URL, die auf den Ort verweist, an dem der Kommentar hinterlassen wurde. **/
8 url: string | null
9 /** Die Benutzer-ID, die den Kommentar hinterlassen hat. Bei SSO mit der Tenant-ID vorangestellt. **/
10 userId: string | null
11 /** Die E-Mail des Benutzers, der den Kommentar hinterlassen hat. **/
12 commenterEmail: string | null
13 /** Der Name des Benutzers, der im Kommentar-Widget angezeigt wird. Bei SSO kann dies displayName sein. **/
14 commenterName: string
15 /** Roher Kommentartext. **/
16 comment: string
17 /** Kommentartext nach dem Parsen. **/
18 commentHTML: string
19 /** Externe ID des Kommentars. **/
20 externalId: string | null
21 /** Die ID des übergeordneten Kommentars. **/
22 parentId: string | null
23 /** Das UTC-Datum, an dem der Kommentar hinterlassen wurde. **/
24 date: UTC_ISO_DateString
25 /** Kombiniertes Karma (up - down) der Stimmen. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** True, wenn der Benutzer beim Kommentieren eingeloggt war, oder den Kommentar verifiziert hat, oder seine Sitzung verifiziert hat, als der Kommentar hinterlassen wurde. **/
30 verified: boolean
31 /** Das UTC-Datum, an dem der Kommentar verifiziert wurde. **/
32 verifiedDate: UTC_ISO_DateString | null
33 /** Ob ein Moderator den Kommentar als geprüft markiert hat. **/
34 reviewed: boolean
35 /** Der Speicherort oder die Base64-Kodierung des Avatars. Nur dann Base64, wenn dies der mit SSO übergebene Wert war. **/
36 avatarSrc: string | null
37 /** Wurde der Kommentar manuell oder automatisch als Spam markiert? **/
38 isSpam: boolean
39 /** Wurde der Kommentar automatisch als Spam markiert? **/
40 aiDeterminedSpam: boolean
41 /** Enthält der Kommentar Bilder? **/
42 hasImages: boolean
43 /** Die Seitenzahl, auf der sich der Kommentar für die Sortierrichtung „Most Relevant“ befindet. **/
44 pageNumber: number | null
45 /** Die Seitenzahl, auf der sich der Kommentar für die Sortierrichtung „Oldest First“ befindet. **/
46 pageNumberOF: number | null
47 /** Die Seitenzahl, auf der sich der Kommentar für die Sortierrichtung „Newest First“ befindet. **/
48 pageNumberNF: number | null
49 /** Wurde der Kommentar automatisch oder manuell genehmigt? **/
50 approved: boolean
51 /** Der Locale-Code (Format: en_us) des Benutzers, als der Kommentar geschrieben wurde. **/
52 locale: string | null
53 /** Die im Kommentar geschriebenen @mentions, die erfolgreich geparst wurden. Leer, wenn keine vorhanden sind. **/
54 mentions: CommentUserMention[]
55 /** Die Domain, von der der Kommentar stammt. **/
56 domain: string | null
57 /** Die mit diesem Kommentar verknüpften Moderationsgruppen-IDs. Leer, wenn keine vorhanden sind. **/
58 moderationGroupIds: string[]
59 /** Die Badges, die neben dem Namen des Kommentierenden bei diesem Kommentar angezeigt werden, zum Zeitpunkt der Erstellung des Ereignisses. Leer, wenn keine vorhanden sind. **/
60 badges: CommentUserBadgeInfo[]
61}
62

Wenn Benutzer in einem Kommentar markiert werden, werden die Informationen in einer Liste namens mentions gespeichert. Jedes Objekt in dieser Liste hat die folgende Struktur.

Das Webhook-Mentions-Objekt
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** Die Benutzer-ID. Bei SSO-Benutzern wird Ihre Tenant-ID vorangestellt. **/
4 id: string
5 /** Der endgültige @mention-Tag-Text, einschließlich des @-Symbols. **/
6 tag: string
7 /** Der ursprüngliche @mention-Tag-Text, einschließlich des @-Symbols. **/
8 rawTag: string
9 /** Welche Art von Benutzer markiert wurde. user = FastComments.com-Konto. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Wenn der Benutzer Benachrichtigungen abbestellt hat, wird dies dennoch auf true gesetzt. **/
12 sent: boolean
13}
14

Jeder Eintrag in der badges-Liste hat die folgende Struktur. Siehe den Badges-Leitfaden für die Badge-Typen.

Das Webhook-Badge-Objekt
Copy CopyRun External Link
1
2interface CommentUserBadgeInfo {
3 /** Die ID des diesem Benutzer verliehenen Badges. **/
4 id: string
5 /** Der Badge-Typ. **/
6 type: number
7 /** Die Badge-Beschreibung, die beim Daraufzeigen mit der Maus angezeigt wird. **/
8 description: string
9 /** Der auf dem Badge angezeigte Text. **/
10 displayLabel?: string | null
11 /** Das für den Badge angezeigte Bild, falls er eines verwendet. **/
12 displaySrc?: string | null
13 backgroundColor?: string | null
14 borderColor?: string | null
15 textColor?: string | null
16 /** Eine zusätzliche CSS-Klasse, die auf den Badge angewendet wird. **/
17 cssClass?: string | null
18}
19

HTTP-Methoden

Sie können die HTTP-Methode für jeden Webhook-Ereignistyp im Admin-Panel konfigurieren:

  • Create-Ereignis: POST oder PUT (Standard: PUT)
  • Update-Ereignis: POST oder PUT (Standard: PUT)
  • Delete-Ereignis: DELETE, POST oder PUT (Standard: DELETE)

Da alle Anfragen eine ID enthalten, sind Create- und Update-Operationen standardmäßig idempotent (PUT). Das Wiederholen derselben Create- oder Update-Anfrage sollte auf Ihrer Seite keine doppelten Objekte erzeugen.

Request-Header

Jede Webhook-Anfrage enthält die folgenden Header:

HeaderBeschreibung
Content-Typeapplication/json
tokenIhr API-Secret
X-FastComments-TimestampUnix-Zeitstempel (Sekunden), wann die Anfrage signiert wurde
X-FastComments-SignatureHMAC-SHA256-Signatur (sha256=<hex>)

Siehe Sicherheit & API-Tokens für Informationen zur Verifizierung der HMAC-Signatur.

Sicherheit & API-Token Internal Link

FastComments Webhook-Anfragen enthalten mehrere Authentifizierungsmechanismen zur Sicherheit.

Gesendete Header

HeaderBeschreibung
tokenIhr API Secret (zur Abwärtskompatibilität)
X-FastComments-TimestampUnix-Zeitstempel (Sekunden), zu dem die Anfrage signiert wurde
X-FastComments-SignatureHMAC-SHA256-Signatur der Payload

HMAC-Signaturüberprüfung (empfohlen)

Wir empfehlen dringend, die HMAC-Signatur zu überprüfen, um sicherzustellen, dass Webhook-Payloads authentisch sind und nicht manipuliert wurden.

Signaturformat: sha256=<hex-encoded-signature>

Wie die Signatur berechnet wird:

  1. Verketten: timestamp + "." + JSON_payload_body
  2. Berechne HMAC-SHA256 mit Ihrem API Secret als Schlüssel
  3. Das Ergebnis hexadezimal kodieren

Beispielüberprüfung (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(req, apiSecret) {
    const timestamp = req.headers['x-fastcomments-timestamp'];
    const signature = req.headers['x-fastcomments-signature'];

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

    // Überprüfe, ob der Zeitstempel aktuell ist (innerhalb von 5 Minuten)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Schutz vor Replay-Angriffen
    }

    // Überprüfe Signatur
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

    return signature === `sha256=${expectedSignature}`;
}

Beispielüberprüfung (Python)

import hmac
import hashlib
import time
import json

def verify_webhook_signature(headers, body, api_secret):
    timestamp = headers.get('X-FastComments-Timestamp')
    signature = headers.get('X-FastComments-Signature')

    if not timestamp or not signature:
        return False

    # Überprüfe, ob der Zeitstempel aktuell ist
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Überprüfe Signatur
    payload = json.dumps(body, separators=(',', ':'))
    message = f"{timestamp}.{payload}"
    expected = hmac.new(
        api_secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return signature == f"sha256={expected}"

Beispielüberprüfung (PHP)

function verifyWebhookSignature($headers, $body, $apiSecret) {
    $timestamp = $headers['X-FastComments-Timestamp'] ?? null;
    $signature = $headers['X-FastComments-Signature'] ?? null;

    if (!$timestamp || !$signature) {
        return false;
    }

    // Überprüfe, ob der Zeitstempel aktuell ist (innerhalb von 5 Minuten)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Überprüfe Signatur
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Legacy-Authentifizierung

Der token-Header, der Ihr API Secret enthält, wird weiterhin zur Abwärtskompatibilität gesendet. Wir empfehlen jedoch, auf die HMAC-Überprüfung umzusteigen, um die Sicherheit zu verbessern, da diese vor Replay-Angriffen schützt.

Verwalten von Webhooks über die API Internal Link

Webhooks können ebenfalls über die REST‑API verwaltet werden. So abonnieren Integrationen wie Zapier Kommentarereignisse, ohne das Dashboard zu berühren, und es folgt dem REST‑Hooks‑Muster: abonnieren, Ereignisse empfangen, abbestellen.

API‑Abonnements existieren neben den im Dashboard konfigurierten Webhooks. Ein Kommentarereignis wird an jeden Webhook geliefert, dessen Domain entspricht, jeweils als eigene Zustellung, unabhängig davon, wie der Webhook erstellt wurde.

Authentifizierung

Jede Anfrage benötigt Ihren API‑Schlüssel im Header x-api-key (oder als Abfrageparameter API_KEY) und Ihre Mandanten‑ID im Abfrageparameter tenantId. Beide werden auf der Seite API‑Geheimnis im Dashboard angezeigt.

Abonnieren

POST https://fastcomments.com/api/v1/webhooks?tenantId=YOUR_TENANT_ID
x-api-key: YOUR_API_KEY
Content-Type: application/json

{
    "url": "https://hooks.zapier.com/hooks/catch/123/abc",
    "event": "comment-created"
}
FeldErforderlichBeschreibung
urlJaEine absolute http- oder https-URL.
eventJacomment-created, comment-updated oder comment-deleted.
domainNeinEine Domain aus Ihrer Kontokonfiguration. Standard ist *, wodurch Ereignisse für jede Domain empfangen werden.
methodNeinPOST (Standard), PUT oder DELETE.

Die Antwort enthält das Abonnement:

{
    "status": "success",
    "webhook": {
        "id": "66f1c4c1e7a2b3d4f5a6b7c8",
        "url": "https://hooks.zapier.com/hooks/catch/123/abc",
        "event": "comment-created",
        "domain": "*",
        "method": "POST",
        "source": "api",
        "enabled": true,
        "createdAt": "2026-09-08T12:00:00.000Z"
    }
}

Das Abonnieren derselben URL für dasselbe Ereignis und dieselbe Domain gibt das bestehende Abonnement zurück, anstatt ein Duplikat zu erstellen, sodass ein Client sicher erneut versuchen kann. Jeder Mandant kann bis zu 50 API‑Abonnements haben.

Auflisten

GET https://fastcomments.com/api/v1/webhooks?tenantId=YOUR_TENANT_ID

Gibt jeden Webhook für den Mandanten zurück, einschließlich der im Dashboard verwalteten ("source": "dashboard"). Filtern Sie mit event, domain oder source.

Abbestellen

DELETE https://fastcomments.com/api/v1/webhooks/SUBSCRIPTION_ID?tenantId=YOUR_TENANT_ID

Das Löschen eines Abonnements verwirft auch alle noch für es in der Warteschlange befindlichen Ereignisse. Nur über die API erstellte Abonnements können auf diese Weise gelöscht werden; ein Dashboard‑Webhook oder eine ID, die in Ihrem Konto nicht existiert, liefert 404 mit dem Code not-found. Dashboard‑Webhooks werden auf der Seite Webhooks bearbeitet.

Nutzdaten und Signatur

Zustellungen verwenden dieselben Nutzdaten wie Dashboard‑Webhooks (siehe Datenstrukturen) und werden mit demselben HMAC‑Verfahren signiert (siehe Sicherheit & API‑Tokens). API‑Abonnements erhalten niemals den veralteten token‑Header, daher prüfen Sie stattdessen den Header X-FastComments-Signature.

Beispiel‑Nutzdaten

GET https://fastcomments.com/api/v1/webhooks/sample-payloads?tenantId=YOUR_TENANT_ID&event=comment-created&limit=3

Gibt die neuesten Kommentare des Kontos exakt in der Form zurück, die eine Zustellung trägt, sodass eine Integration reale Beispieldaten anzeigen kann, bevor das erste Ereignis eintrifft. event ist optional und wird nur validiert, da jedes Ereignis dasselbe Kommentarobjekt liefert. limit hat standardmäßig den Wert 3 und akzeptiert Werte von 1 bis 10. Kosten: 2 API‑Credits.

{
    "status": "success",
    "payloads": [
        {
            "id": "66f1c4c1e7a2b3d4f5a6b7c8",
            "urlId": "https://example.com/blog/hello-world",
            "commenterName": "Jane Reader",
            "comment": "Great article!",
            "date": "2026-09-08T12:00:00.000Z",
            "approved": true
        }
    ]
}

Antworten mit 410 Gone

Wenn der Endpunkt eines API‑Abonnements mit HTTP 410 Gone antwortet, behandelt FastComments dies als Abbestellung: Das Abonnement wird zusammen mit seinen wartenden Ereignissen gelöscht und es werden keine weiteren Zustellungen versucht. In dem Dashboard konfigurierten Webhooks werden niemals automatisch gelöscht; für sie ist ein 410 ein gewöhnlicher Fehler. Jeder andere Fehlstatus wird erneut versucht und führt schließlich zur Deaktivierung des Webhooks, wie in Funktionsweise & Umgang mit Wiederholungen beschrieben.

Dashboard

API‑Abonnements erscheinen in der Webhooks‑Liste mit der Quelle API, wo ein Administrator sie bearbeiten, deaktivieren, wieder aktivieren oder löschen kann.

Zum Abschluss

Dies schließt unsere Webhooks-Dokumentation ab.

Wir hoffen, dass Sie die FastComments-Webhook-Integration leicht verständlich finden und schnell einrichten können.

Wenn Sie der Meinung sind, dass unsere Dokumentation Lücken aufweist, teilen Sie uns dies unten mit.