FastComments.com

Webhooks


Med FastComments er det muligt at kalde et API-endpoint, når en kommentar tilføjes, opdateres eller fjernes fra vores system.

Vi opnår dette med asynkrone webhooks over HTTP/HTTPS.


Hvad er Webhooks Internal Link

En Webhook er en mekanisme, eller en integration, mellem to systemer hvor "produceren" (FastComments) udløser en begivenhed som "forbrugeren" (dig) modtager via et API-opkald.

Understøttede begivenheder og ressourcer Internal Link


FastComments understøtter kun webhooks for Comment-ressourcen.

Vi understøtter webhooks for oprettelse af kommentarer, fjernelse og opdatering.

Hver af disse betragtes som separate hændelser i vores system og har derfor forskellige semantikker og strukturer for webhook‑hændelserne.

Et vilkårligt antal endpoints kan abonnere på den samme hændelse, fra dashboardet eller via API'en (se Administrere Webhooks via API'en). Hver webhook leveres uafhængigt.


Testning Internal Link

De nye og redigerings‑webhook‑sider har en Send Test Payload‑knap, der sender en anmodning til den URL, der i øjeblikket er i formularen, uanset om den er gemt eller ej. Create‑ og Update‑begivenhederne sender et dummy‑WebhookComment‑objekt, mens test af Delete vil sende et dummy‑anmodnings‑body med kun et ID.

Verificering af payloads

Når du tester din webhook‑integration, skal du verificere, at de indgående anmodninger indeholder følgende headers:

  1. X-FastComments-Timestamp - Unix‑tidsstempel (sekunder)
  2. X-FastComments-Signature - HMAC‑SHA256‑signatur

Webhooks oprettet før signaturskemaet blev introduceret modtager også en token‑header, der indeholder din API‑hemmelighed. Nye webhooks gør det ikke.

Brug HMAC‑signaturverificering for at sikre, at payloads er ægte.

Testværktøjer

Du kan bruge værktøjer som webhook.site eller ngrok til at inspicere indgående webhook‑payloads under udvikling.

Begivenhedstyper

  • Create Event: Udløses, når en ny kommentar oprettes.
  • Update Event: Udløses, når en kommentar redigeres.
  • Delete Event: Udløses, når en kommentar slettes.

Hver webhook er knyttet til én begivenhed og én HTTP‑metode (POST, PUT eller DELETE). Hver begivenhed inkluderer de fulde kommentardata i anmodnings‑body’en (se Data Structures for payload‑formatet).

Datastrukturer Internal Link

The only structure sent via webhooks is the WebhookComment object, outlined in TypeScript below.

WebhookComment-objektets struktur

The "Create" Event Structure

The "create" event request body is a WebhookComment object.

The "Update" Event Structure

The "update" event request body is a WebhookComment object.

The "Delete" Event Structure

The "delete" event request body is a WebhookComment object.

Change as of Nov 14th 2023
Previously the "delete" event request body only contained the comment id. It now contains the full comment at the time of deletion.

Every key is always present in the body. When the comment has no value for a field the body carries null (or false for booleans and [] for lists), so the shape of a delivery never varies from one comment to the next.

WebhookComment-objektet
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

When users are tagged in a comment, the information is stored in a list called mentions. Each object in that list has the following structure.

Webhook-mentions-objektet
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-metoder

Du kan konfigurere HTTP-metoden for hver webhook-begivenhedstype i administrationspanelet:

  • Create-begivenhed: POST eller PUT (standard: PUT)
  • Update-begivenhed: POST eller PUT (standard: PUT)
  • Delete-begivenhed: DELETE, POST eller PUT (standard: DELETE)

Da alle anmodninger indeholder et ID, er Create- og Update-operationer idempotente som standard (PUT). Gentagelse af den samme Create- eller Update-anmodning bør ikke oprette duplikerede objekter på din side.

Anmodnings‑headers

Hver webhook-anmodning inkluderer følgende headers:

HeaderDescription
Content-Typeapplication/json
tokenDin API-hemmelighed
X-FastComments-TimestampUnix-tidsstempel (sekunder) da anmodningen blev signeret
X-FastComments-SignatureHMAC-SHA256-signatur (sha256=<hex>)

Se Sikkerhed & API‑tokens for information om verifikation af HMAC-signaturen.

Sikkerhed og API‑tokens Internal Link

FastComments webhook-forespørgsler indeholder flere autentificeringsmekanismer for sikkerhed.

Sendte headere

HeaderBeskrivelse
tokenDin API Secret (for bagudkompatibilitet)
X-FastComments-TimestampUnix-tidsstempel (sekunder) da anmodningen blev signeret
X-FastComments-SignatureHMAC-SHA256-signatur af payloaden

HMAC-signaturverifikation (Anbefalet)

Vi anbefaler kraftigt at verificere HMAC-signaturen for at sikre, at webhook-payloads er autentiske og ikke er blevet manipuleret med.

Signaturformat: sha256=<hex-encoded-signature>

Hvordan signaturen beregnes:

  1. Sammenkæd: timestamp + "." + JSON_payload_body
  2. Beregn HMAC-SHA256 ved at bruge din API Secret som nøgle
  3. Hex-enkodér resultatet

Eksempel på verifikation (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;
    }

    // Bekræft at tidsstemplet er nyligt (inden for 5 minutter)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Forebyggelse af replay-angreb
    }

    // Bekræft signatur
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

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

Eksempel på verifikation (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

    # Bekræft at tidsstemplet er nyligt
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Bekræft 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}"

Eksempel på verifikation (PHP)

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

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

    // Bekræft at tidsstemplet er nyligt (inden for 5 minutter)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Bekræft signatur
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Ældre autentificering

token-headeren, der indeholder din API Secret, sendes stadig for bagudkompatibilitet. Vi anbefaler dog at migrere til HMAC-verifikation for forbedret sikkerhed, da det beskytter mod replay-angreb.


Håndtering af Webhooks via API'en Internal Link

Webhooks kan også administreres via REST API'et. Sådan kan integrationer som Zapier abonnere på kommentarhændelser uden at røre ved dashboardet, og det følger REST Hooks‑mønsteret: abonnere, modtage hændelser, afmelde.

API‑abonnementer lever side om side med de webhooks, der er konfigureret i dashboardet. En kommentarhændelse leveres til hver webhook, der matcher dens domæne, hver for sig, uanset hvordan webhooken blev oprettet.

Godkendelse

Hver anmodning kræver din API‑nøgle i x-api-key‑headeren (eller API_KEY‑forespørgselsparameteren) og dit lejer‑ID i tenantId‑forespørgselsparameteren. Begge vises på siden API Secret i dashboardet.

Abonner

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"
}
FeltPåkrævetBeskrivelse
urlJaEn absolut http‑URL eller https‑URL.
eventJacomment‑created, comment‑updated eller comment‑deleted.
domainNejEt domæne fra din kontokonfiguration. Standard er *, som modtager hændelser for hvert domæne.
methodNejPOST (standard), PUT eller DELETE.

Hvis du abonnerer på den samme URL til den samme hændelse og domæne igen, returneres det eksisterende abonnement i stedet for at oprette en duplikat, så en klient trygt kan prøve igen. Hver lejer kan have op til 50 API‑abonnementer.

Liste

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

Returnerer alle webhooks for lejeren, inklusive dem, der administreres i dashboardet ("source": "dashboard"). Filtrer med event, domain eller source.

Afmeld

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

Sletning af et abonnement kasserer også eventuelle hændelser, der stadig er i kø for det. Kun abonnementer oprettet via API'et kan slettes på denne måde; en dashboard‑webhook eller et id, der ikke findes på din konto, svarer med 404 og koden not-found. Dashboard‑webhooks redigeres på siden Webhooks.

Payloads og signering

Leverancer bruger den samme payload som dashboard‑webhooks (se Data Structures) og er signeret med det samme HMAC‑skema (se Security & API Tokens). API‑abonnementer modtager aldrig den ældre token‑header, så verificer i stedet X-FastComments-Signature‑headeren.

Eksempel‑payloads

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

Returnerer kontoens seneste kommentarer i præcis den form, en levering har, så en integration kan vise reelle eksempeldata, før den første hændelse ankommer. event er valgfri og kun valideret, da hver hændelse leverer det samme kommentarobjekt. limit er standard 3 og accepterer 1 til 10. Koster 2 API‑kreditter.

{
    "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
        }
    ]
}

Svar med 410 Gone

Hvis en API‑abonnements endpoint svarer med HTTP 410 Gone, betragter FastComments det som en afmelding: abonnementet slettes sammen med dets køede hændelser, og der foretages ingen yderligere leveringer. Webhooks konfigureret i dashboardet slettes aldrig automatisk; for dem er en 410 en almindelig fejl. Alle andre fejlkoder forsøges igen og deaktiverer til sidst webhooken, som beskrevet i Sådan fungerer det & Håndtering af genforsøg.

Dashboard

API‑abonnementer vises i listen over Webhooks med kilden API, hvor en administrator kan redigere, deaktivere, genaktivere eller slette dem.


Afslutningsvis

Dette afslutter vores Webhooks-dokumentation.

Vi håber, du synes, at FastComments Webhook-integrationen er nem at forstå og hurtig at sætte op.

Hvis du mener, at du har fundet mangler i vores dokumentation, så lad os det vide nedenfor.