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 und bearbeitenden Webhook‑Seiten haben einen Send Test Payload‑Button, der eine Anfrage an die aktuell im Formular angegebene URL sendet, unabhängig davon, ob sie gespeichert wurde. 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.

Verifying Payloads

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

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

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

Verwenden Sie die HMAC‑Signatur‑Verifizierung, um sicherzustellen, dass Payloads authentisch sind.

Testing Tools

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

Event Types

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

Jeder Webhook ist an ein Ereignis und eine HTTP‑Methode (POST, PUT oder DELETE) gebunden. Jedes Ereignis enthält die vollständigen Kommentardaten im Request‑Body (siehe Data Structures 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 Anforderungstext des "create"-Ereignisses ist ein WebhookComment-Objekt.

Die Struktur des "Update"-Ereignisses

Der Anforderungstext des "update"-Ereignisses ist ein WebhookComment-Objekt.

Die Struktur des "Delete"-Ereignisses

Der Anforderungstext des "delete"-Ereignisses ist ein WebhookComment-Objekt.

Änderung ab 14. November 2023
Früher enthielt der Anforderungstext des "delete"-Ereignisses nur die Kommentar-ID. Jetzt enthält er den vollständigen Kommentar zum Zeitpunkt der Löschung.

Jeder Schlüssel ist immer im Body vorhanden. Wenn der Kommentar keinen Wert für ein Feld hat, enthält der Body null (oder false für Booleans und [] für Listen), sodass die Struktur einer Lieferung nie von einem Kommentar zum anderen variiert.

Das WebhookComment-Objekt
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** The id of the comment. **/
4 id: string
5 /** The id or URL that identifies the comment thread. Normalized. **/
6 urlId: string
7 /** The URL that points to where the comment was left. **/
8 url: string | null
9 /** The user id that left the comment. If SSO, prefixed with tenant id. **/
10 userId: string | null
11 /** The email of the user left the comment. **/
12 commenterEmail: string | null
13 /** The name of the user that shows in the comment widget. With SSO, can be displayName. **/
14 commenterName: string
15 /** Raw comment text. **/
16 comment: string
17 /** Comment text after parsing. **/
18 commentHTML: string
19 /** Comment external id. **/
20 externalId: string | null
21 /** The id of the parent comment. **/
22 parentId: string | null
23 /** The UTC date when the comment was left. **/
24 date: UTC_ISO_DateString
25 /** Combined karma (up - down) of votes. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** True if the user was logged in when they commented, or their verified the comment, or if they verified their session when the comment was left. **/
30 verified: boolean
31 /** The UTC date when the comment was verified. **/
32 verifiedDate: UTC_ISO_DateString | null
33 /** If a moderator marked the comment reviewed. **/
34 reviewed: boolean
35 /** The location, or base64 encoding, of the avatar. Will only be base64 if that was the value passed with SSO. **/
36 avatarSrc: string | null
37 /** Was the comment manually or automatically marked as spam? **/
38 isSpam: boolean
39 /** Was the comment automatically marked as spam? **/
40 aiDeterminedSpam: boolean
41 /** Are there images in the comment? **/
42 hasImages: boolean
43 /** The page number the comment is on for the "Most Relevant" sort direction. **/
44 pageNumber: number | null
45 /** The page number the comment is on for the "Oldest First" sort direction. **/
46 pageNumberOF: number | null
47 /** The page number the comment is on for the "Newest First" sort direction. **/
48 pageNumberNF: number | null
49 /** Was the comment approved automatically or manually? **/
50 approved: boolean
51 /** The locale code (format: en_us) of the user when the comment was written. **/
52 locale: string | null
53 /** The @mentions written in the comment that were successfully parsed. Empty when there are none. **/
54 mentions: CommentUserMention[]
55 /** The domain the comment is from. **/
56 domain: string | null
57 /** The moderation group ids associated with this comment. Empty when there are none. **/
58 moderationGroupIds: string[]
59}
60

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 /** The user id. For SSO users, this will have your tenant id prefixed. **/
4 id: string
5 /** The final @mention tag text, including the @ symbol. **/
6 tag: string
7 /** The original @mention tag text, including the @ symbol. **/
8 rawTag: string
9 /** What type of user was tagged. user = FastComments.com account. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** If the user opts out of notifications, this will still be set to true. **/
12 sent: boolean
13}
14

HTTP-Methoden

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

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

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

Anforderungs-Header

Jede Webhook-Anfrage enthält die folgenden Header:

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

Siehe Sicherheit & API-Token für Informationen zur Überprüfung 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.