FastComments.com


Са FastComments-ом могуће је позвати API endpoint кад год се коментар дода, ажурира или уклони из нашег система.

Ово остварујемо помоћу асинхроних webhooks преко HTTP/HTTPS.


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

Webhook је механизам, или интеграција, између два система где "произвођач" (FastComments) покреће догађај који "потрошач" (Ви) прима путем API позива.

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


FastComments подржава вебхукове само за ресурс Comment.

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

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


Тестирање Internal Link

У администрацији Webhooks постоје дугмад Send Test Payload за сваку врсту догађаја (Create, Update, Delete). Догађаји Create и Update шаљу привремени WebhookComment објекат, док тестирање Delete шаље пробно тело захтева са само једним ID-јем.

Верификација корисности порука

Када тестирате вашу webhook интеграцију, проверите да долазни захтеви садрже следеће заглавља:

  1. token - Ваш API тајни кључ
  2. X-FastComments-Timestamp - Unix timestamp (у секундама)
  3. X-FastComments-Signature - HMAC-SHA256 потпис

Користите проверу HMAC потписа да бисте осигурали да су подаци у порукама аутентични.

Алатке за тестирање

Можете користити алатке као што су webhook.site или ngrok да бисте прегледали долазне webhook payload-ове током развоја.

Врсте догађаја

  • Create Event: Покреће се када се креише нови коментар. Подразумевана метода: PUT
  • Update Event: Покреће се када се коментар уреди. Подразумевана метода: PUT
  • Delete Event: Покреће се када се коментар обрише. Подразумевана метода: DELETE

Сваки догађај укључује све податке коментара у телу захтева (погледајте Структуре података за формат payload-а).

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

Једина структура која се шаље преко вебхукова је објекат WebhookComment, описан у TypeScript-у испод.

Структура објекта WebhookComment

Структура догађаја "Create"

Тело захтева за догађај "create" је објекат WebhookComment.

Структура догађаја "Update"

Тело захтева за догађај "update" је објекат WebhookComment.

Структура догађаја "Delete"

Тело захтева за догађај "delete" је објекат WebhookComment.

Промена од 14. новембра 2023.
Пре тога, тело захтева за догађај "delete" садржало је само id коментара. Сада садржи цео коментар у тренутку брисања.
Објекат WebhookComment
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** ИД коментара. **/
4 id: string
5 /** ИД или URL који идентификује нит коментара. Нормализовано. **/
6 urlId: string
7 /** URL који показује где је коментар остављен. **/
8 url?: string
9 /** ИД корисника који је оставио коментар. Ако је SSO, са префиксом tenant id. **/
10 userId?: string
11 /** Е-пошта корисника који је оставио коментар. **/
12 commenterEmail?: string
13 /** Име корисника које се приказује у видгету за коментаре. Са SSO, може бити displayName. **/
14 commenterName: string
15 /** Непроцесирани текст коментара. **/
16 comment: string
17 /** Текст коментара након парсирања. **/
18 commentHTML: string
19 /** Спољашњи id коментара. **/
20 externalId?: string
21 /** ИД родитељског коментара. **/
22 parentId?: string | null
23 /** UTC датум када је коментар остављен. **/
24 date: UTC_ISO_DateString
25 /** Сумирани карама (за - против) гласова. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** True ако је корисник био пријављен када је коментарисао, или ако је верификовао коментар, или ако је верификовао своју сесију када је коментар остављен. **/
30 verified: boolean
31 /** Датум када је коментар верификован. **/
32 verifiedDate?: number
33 /** Ако је модератор означио коментар као прегледан. **/
34 reviewed: boolean
35 /** Локација, или base64 енкодовање, аватара. Биће base64 само ако је та вредност послата са SSO. **/
36 avatarSrc?: string
37 /** Да ли је коментар ручно или аутоматски означен као спам? **/
38 isSpam: boolean
39 /** Да ли је коментар аутоматски означен као спам? **/
40 aiDeterminedSpam: boolean
41 /** Да ли постоје слике у коментару? **/
42 hasImages: boolean
43 /** Број странице на којој се коментар налази за сортирање "Most Relevant". **/
44 pageNumber: number
45 /** Број странице на којој се коментар налази за сортирање "Oldest First". **/
46 pageNumberOF: number
47 /** Број странице на којој се коментар налази за сортирање "Newest First". **/
48 pageNumberNF: number
49 /** Да ли је коментар одобрен аутоматски или ручно? **/
50 approved: boolean
51 /** Код локала (формат: en_us) корисника када је коментар написан. **/
52 locale: string
53 /** @помене написане у коментару које су успешно парсиране. **/
54 mentions?: CommentUserMention[]
55 /** Домен са којег потиче коментар. **/
56 domain?: string
57 /** Опциони списак id-ева група модерације повезаних са овим коментаром. **/
58 moderationGroupIds?: string[]|null
59}
60

Када су корисници означени у коментару, информације се чувају у списку који се зове mentions. Сваки објекат у том списку има следећу структуру.

Објекат помена Webhook
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** ИД корисника. За SSO кориснике, овоме ће бити додат префикс tenant id. **/
4 id: string
5 /** Коначан текст @mention ознаке, укључујући симбол @. **/
6 tag: string
7 /** Оригинални текст @mention ознаке, укључујући симбол @. **/
8 rawTag: string
9 /** Каквa врста корисника је означена. user = FastComments.com account. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Ако се корисник одјави са обавештења, ово ће и даље бити постављено на true. **/
12 sent: boolean
13}
14

HTTP методи

Можете конфигурисати HTTP метод за сваку врсту вебхук догађаја у админ панелу:

  • Create догађај: POST или PUT (подразумевано: PUT)
  • Update догађај: POST или PUT (подразумевано: PUT)
  • Delete догађај: DELETE, POST, или PUT (подразумевано: DELETE)

Пошто сви захтеви садрже ID, операције Create и Update су подразумевано идемпотентне (PUT). Понављање истог Create или Update захтева не би требало да креира дупликат објеката на вашој страни.

Заглавља захтева

Сваки вебхук захтев укључује следећа заглавља:

Header Description
Content-Type application/json
token Ваш API тајни кључ
X-FastComments-Timestamp Unix временска ознака (у секундама) када је захтев потписан
X-FastComments-Signature HMAC-SHA256 потпис (sha256=<hex>)

Погледајте Безбедност и API токени за информације о верификацији HMAC потписа.

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

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

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

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

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

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

Формат потписа: 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 верификацију због побољшане безбедности јер штити од replay напада.


У закључку

Овим се завршава наша Webhooks документација.

Надамо се да ће вам интеграција FastComments Webhook бити лака за разумевање и брза за подешавање.

Ако сматрате да сте пронашли било какве недостатке у нашој документацији, јавите нам у наставку.