FastComments.com


Uz FastComments moguće je pozvati API endpoint kad god se komentar doda, ažurira ili ukloni iz našeg sistema.

Ovo postižemo asinhronim webhookovima preko HTTP/HTTPS.


Шта су вебхукови Internal Link

A Webhook je mehanizam, odnosno integracija, između dva sistema gdje "proizvođač" (FastComments) pokreće događaj koji "potrošač" (Vi) konzumira putem API poziva.

Подржани догађаји и ресурси Internal Link

FastComments подржава webhook-ове само за ресурс Comment.

Подржавамо webhook-ове за креирање, уклањање и ажурирање коментара.

Сваки од ових се сматра засебним догађајем у нашем систему и као такав има различиту семантику и структуру за webhook догађаје.

Тестирање Internal Link

U Webhooks administraciji postoje dugmad Send Test Payload za svaki tip događaja (Kreiranje, Ažuriranje, Brisanje). Događaji Kreiranja i Ažuriranja šalju lažni objekat WebhookComment, dok testiranje Brisanja pošalje lažno tijelo zahtjeva koje sadrži samo ID.

Verifikacija payloada

Tokom testiranja vaše webhook integracije, provjerite da dolazni zahtjevi sadrže sljedeća zaglavlja:

  1. token - Vaš API tajni ključ
  2. X-FastComments-Timestamp - Unix vremenska oznaka (sekunde)
  3. X-FastComments-Signature - HMAC-SHA256 potpis

Koristite verifikaciju HMAC potpisa kako biste osigurali da su payloadi autentični.

Alati za testiranje

Možete koristiti alate kao što su webhook.site ili ngrok za pregled dolaznih webhook payloada tokom razvoja.

Tipovi događaja

  • Događaj kreiranja: Pokreće se kada se kreira novi komentar. Podrazumijevana metoda: PUT
  • Događaj ažuriranja: Pokreće se kada se komentar izmijeni. Podrazumijevana metoda: PUT
  • Događaj brisanja: Pokreće se kada se komentar obriše. Podrazumijevana metoda: DELETE

Svaki događaj uključuje pune podatke komentara u tijelu zahtjeva (pogledajte Strukture podataka za format payloada).

Структуре података Internal Link

Jedina struktura koja se šalje putem webhook-ova je objekat WebhookComment, prikazan u TypeScript-u ispod.

Struktura objekta WebhookComment

Struktura događaja "create"

Tijelo zahtjeva za događaj "create" je objekat WebhookComment.

Struktura događaja "update"

Tijelo zahtjeva za događaj "update" je objekat WebhookComment.

Struktura događaja "delete"

Tijelo zahtjeva za događaj "delete" je objekat WebhookComment.

Promjena od 14. novembra 2023.
Ranije je tijelo zahtjeva za događaj "delete" sadržavalo samo id komentara. Sada sadrži kompletan komentar u trenutku brisanja.
Objekat WebhookComment
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
9 /** The user id that left the comment. If SSO, prefixed with tenant id. **/
10 userId?: string
11 /** The email of the user left the comment. **/
12 commenterEmail?: string
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
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 /** Date when the comment was verified. **/
32 verifiedDate?: number
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
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
45 /** The page number the comment is on for the "Oldest First" sort direction. **/
46 pageNumberOF: number
47 /** The page number the comment is on for the "Newest First" sort direction. **/
48 pageNumberNF: number
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
53 /** The @mentions written in the comment that were successfully parsed. **/
54 mentions?: CommentUserMention[]
55 /** The domain the comment is from. **/
56 domain?: string
57 /** The optional list of moderation group ids associated with this comment. **/
58 moderationGroupIds?: string[]|null
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.

Objekat pomena u webhooku
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 Methods

You can configure the HTTP method for each webhook event type in the admin panel:

  • Create Event: POST or PUT (default: PUT)
  • Update Event: POST or PUT (default: PUT)
  • Delete Event: DELETE, POST, or PUT (default: DELETE)

Since all requests contain an ID, Create and Update operations are idempotent by default (PUT). Repeating the same Create or Update request should not create duplicate objects on your side.

Request Headers

Each webhook request includes the following headers:

Header Description
Content-Type application/json
token Vaš API Secret
X-FastComments-Timestamp Unix timestamp (sekunde) kada je zahtjev potpisan
X-FastComments-Signature HMAC-SHA256 potpis (sha256=<hex>)

See Sigurnost i API tokeni for information on verifying the HMAC signature.

Безбједност и API токени Internal Link

FastComments webhook захтјеви укључују више механизама аутентификације за безбједност.

Заглавља која се шаљу

Header Description
token Ваш API Secret (ради повратне компатибилности)
X-FastComments-Timestamp Unix временска ознака (у секундама) када је захтјев потписан
X-FastComments-Signature HMAC-SHA256 потпис садржаја

Верификација HMAC потписа (Препоручено)

Снажно препоручујемо верификацију HMAC потписа како бисте били сигурни да су подаци webhook-а аутентични и да им није промијењен садржај.

Формат потписа: sha256=<hex-encoded-signature>

Како се потпис рачуна:

  1. Конкатенишите: timestamp + "." + JSON_payload_body
  2. Израчунајте HMAC-SHA256 користећи ваш API Secret као кључ
  3. Хекс-енкодирајте резултат

Примјер верификације (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;
    }

    // Верификујте да је временска ознака недавна (у року од 5 минута)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Спречавање replay напада
    }

    // Верификујте потпис
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

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

Примјер верификације (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

    # Верификујте да је временска ознака недавна
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Верификујте потпис
    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}"

Примјер верификације (PHP)

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

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

    // Верификујте да је временска ознака недавна (у року од 5 минута)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Верификујте потпис
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Насљедна аутентификација

Заглавље token које садржи ваш API Secret и даље се шаље ради повратне компатибилности. Међутим, препоручујемо прелазак на HMAC верификацију ради побољшане безбједности јер штити од поновљених напада.


Zaključak

Ovo zaključuje našu dokumentaciju za Webhooks.

Nadamo se da je FastComments Webhook integracija laka za razumijevanje i brza za postavljanje.

Ako smatrate da ste uočili bilo kakve nedostatke u našoj dokumentaciji, obavijestite nas u nastavku.