FastComments.com

Webhooks


Avec FastComments, il est possible d'appeler un point de terminaison d'API chaque fois qu'un commentaire est ajouté, mis à jour ou supprimé de notre système.

Nous y parvenons grâce à des webhooks asynchrones via HTTP/HTTPS.


Qu'est-ce que les webhooks Internal Link

Un Webhook est un mécanisme, ou une intégration, entre deux systèmes où le "producteur" (FastComments) déclenche un événement que le "consommateur" (Vous) consomme via un appel d'API.

Événements et ressources pris en charge Internal Link


FastComments prend en charge les webhooks uniquement pour la ressource Comment.

Nous prenons en charge les webhooks pour la création, la suppression et la mise à jour des commentaires.

Chacun de ces cas est considéré comme un événement distinct dans notre système et possède donc des sémantiques et des structures différentes pour les événements webhook.

Un nombre quelconque de points de terminaison peut s'abonner au même événement, depuis le tableau de bord ou via l'API (voir Gestion des webhooks via l'API). Chaque webhook est livré indépendamment.


Tests Internal Link

Les nouvelles pages de webhook et les pages d'édition disposent d'un bouton Send Test Payload qui envoie une requête à l'URL actuellement dans le formulaire, qu'elle ait été enregistrée ou non. Les événements Create et Update envoient un objet WebhookComment factice, tandis que le test de Delete enverra un corps de requête factice contenant uniquement un ID.

Vérification des charges utiles

Lors du test de votre intégration webhook, vérifiez que les requêtes entrantes incluent les en‑têtes suivants :

  1. X-FastComments-Timestamp – horodatage Unix (secondes)
  2. X-FastComments-Signature – signature HMAC‑SHA256

Les webhooks créés avant l’introduction du schéma de signature reçoivent également un en‑tête token contenant votre secret d’API. Les nouveaux webhooks ne le font pas.

Utilisez la vérification de signature HMAC pour garantir l’authenticité des charges utiles.

Outils de test

Vous pouvez utiliser des outils comme webhook.site ou ngrok pour inspecter les charges utiles webhook entrantes pendant le développement.

Types d'événements

  • Create Event : déclenché lorsqu’un nouveau commentaire est créé.
  • Update Event : déclenché lorsqu’un commentaire est modifié.
  • Delete Event : déclenché lorsqu’un commentaire est supprimé.

Chaque webhook est associé à un seul événement et à une méthode HTTP (POST, PUT ou DELETE). Chaque événement inclut les données complètes du commentaire dans le corps de la requête (voir Data Structures pour le format de la charge utile).


Structures de données Internal Link

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

Structure de l'objet WebhookComment

Structure de l'événement "Create"

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

Structure de l'événement "Update"

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

Structure de l'événement "Delete"

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

Modification à partir du 14 nov. 2023
Auparavant, le corps de la requête de l'événement "delete" ne contenait que l'ID du commentaire. Il contient maintenant le commentaire complet au moment de la suppression.

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.

Chaque clé est toujours présente dans le corps. Lorsqu'un commentaire n'a pas de valeur pour un champ, le corps contient null (ou false pour les booléens et [] pour les listes), de sorte que la forme d'une livraison ne varie jamais d'un commentaire à l'autre.

L'objet WebhookComment
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** L'ID du commentaire. **/
4 id: string
5 /** L'ID ou l'URL qui identifie le fil de commentaires. Normalisé. **/
6 urlId: string
7 /** L'URL qui pointe vers l'endroit où le commentaire a été laissé. **/
8 url: string | null
9 /** L'ID utilisateur qui a laissé le commentaire. Si SSO, préfixé avec l'ID du locataire. **/
10 userId: string | null
11 /** L'email de l'utilisateur qui a laissé le commentaire. **/
12 commenterEmail: string | null
13 /** Le nom de l'utilisateur affiché dans le widget de commentaire. Avec SSO, peut être displayName. **/
14 commenterName: string
15 /** Texte brut du commentaire. **/
16 comment: string
17 /** Texte du commentaire après analyse. **/
18 commentHTML: string
19 /** ID externe du commentaire. **/
20 externalId: string | null
21 /** L'ID du commentaire parent. **/
22 parentId: string | null
23 /** La date UTC à laquelle le commentaire a été laissé. **/
24 date: UTC_ISO_DateString
25 /** Karma combiné (up - down) des votes. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** Vrai si l'utilisateur était connecté lorsqu'il a commenté, ou s'il a vérifié le commentaire, ou s'il a vérifié sa session lorsque le commentaire a été laissé. **/
30 verified: boolean
31 /** La date UTC à laquelle le commentaire a été vérifié. **/
32 verifiedDate: UTC_ISO_DateString | null
33 /** Si un modérateur a marqué le commentaire comme revu. **/
34 reviewed: boolean
35 /** L'emplacement, ou l'encodage base64, de l'avatar. Sera uniquement base64 si c'était la valeur transmise avec SSO. **/
36 avatarSrc: string | null
37 /** Le commentaire a-t-il été marqué manuellement ou automatiquement comme spam ? **/
38 isSpam: boolean
39 /** Le commentaire a-t-il été marqué automatiquement comme spam ? **/
40 aiDeterminedSpam: boolean
41 /** Y a-t-il des images dans le commentaire ? **/
42 hasImages: boolean
43 /** Le numéro de page du commentaire pour le tri « Most Relevant ». **/
44 pageNumber: number | null
45 /** Le numéro de page du commentaire pour le tri « Oldest First ». **/
46 pageNumberOF: number | null
47 /** Le numéro de page du commentaire pour le tri « Newest First ». **/
48 pageNumberNF: number | null
49 /** Le commentaire a-t-il été approuvé automatiquement ou manuellement ? **/
50 approved: boolean
51 /** Le code de locale (format : en_us) de l'utilisateur lorsque le commentaire a été rédigé. **/
52 locale: string | null
53 /** Les @mentions écrites dans le commentaire qui ont été analysées avec succès. Vide lorsqu'il n'y en a aucune. **/
54 mentions: CommentUserMention[]
55 /** Le domaine d'où provient le commentaire. **/
56 domain: string | null
57 /** Les IDs des groupes de modération associés à ce commentaire. Vide lorsqu'il n'y en a aucun. **/
58 moderationGroupIds: string[]
59}
60

Lorsque des utilisateurs sont mentionnés dans un commentaire, l'information est stockée dans une liste appelée mentions. Chaque objet de cette liste a la structure suivante.

L'objet Webhook Mentions
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** L'ID utilisateur. Pour les utilisateurs SSO, il sera préfixé avec votre ID de locataire. **/
4 id: string
5 /** Le texte final de la balise @mention, incluant le symbole @. **/
6 tag: string
7 /** Le texte original de la balise @mention, incluant le symbole @. **/
8 rawTag: string
9 /** Quel type d'utilisateur a été mentionné. user = compte FastComments.com. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Si l'utilisateur se désinscrit des notifications, cela restera à true. **/
12 sent: boolean
13}
14

Méthodes HTTP

Vous pouvez configurer la méthode HTTP pour chaque type d'événement webhook dans le panneau d'administration :

  • Événement de création : POST ou PUT (par défaut : PUT)
  • Événement de mise à jour : POST ou PUT (par défaut : PUT)
  • Événement de suppression : DELETE, POST ou PUT (par défaut : DELETE)

Comme toutes les requêtes contiennent un ID, les opérations de création et de mise à jour sont idempotentes par défaut (PUT). Répéter la même requête de création ou de mise à jour ne doit pas créer d'objets en double de votre côté.

En-têtes de requête

Chaque requête webhook inclut les en-têtes suivants :

HeaderDescription
Content-Typeapplication/json
tokenVotre secret d'API
X-FastComments-TimestampHorodatage Unix (secondes) lorsque la requête a été signée
X-FastComments-SignatureSignature HMAC‑SHA256 (sha256=<hex>)

Voir Sécurité et jetons d'API pour plus d'informations sur la vérification de la signature HMAC.

Sécurité et jetons d'API Internal Link

Les requêtes webhook FastComments incluent plusieurs mécanismes d'authentification pour la sécurité.

En-têtes envoyés

En-têteDescription
tokenVotre Secret d'API (pour compatibilité ascendante)
X-FastComments-TimestampHorodatage Unix (secondes) indiquant quand la requête a été signée
X-FastComments-SignatureSignature HMAC-SHA256 de la charge utile

Vérification de la signature HMAC (recommandée)

Nous recommandons fortement de vérifier la signature HMAC pour garantir que les charges utiles des webhooks sont authentiques et n'ont pas été altérées.

Format de la signature : sha256=<hex-encoded-signature>

Comment la signature est calculée :

  1. Concaténez : timestamp + "." + JSON_payload_body
  2. Calculez le HMAC-SHA256 en utilisant votre Secret d'API comme clé
  3. Encodez le résultat en hexadécimal

Exemple de vérification (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;
    }

    // Vérifier que l'horodatage est récent (moins de 5 minutes)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Prévention des attaques par rejeu
    }

    // Vérifier la signature
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

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

Exemple de vérification (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

    # Vérifier que l'horodatage est récent
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Vérifier la signature
    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}"

Exemple de vérification (PHP)

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

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

    // Vérifier que l'horodatage est récent (moins de 5 minutes)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Vérifier la signature
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Authentification héritée

L'en-tête token contenant votre Secret d'API est toujours envoyé pour assurer la compatibilité ascendante. Cependant, nous recommandons de migrer vers la vérification HMAC pour une sécurité renforcée, car elle protège contre les attaques par rejeu.


Gestion des webhooks via l'API Internal Link

Webhooks peuvent également être gérés via l'API REST. C’est ainsi que des intégrations comme Zapier s’abonnent aux événements de commentaires sans toucher au tableau de bord, et cela suit le modèle REST Hooks : s’abonner, recevoir des événements, se désabonner.

Les abonnements API coexistent avec les webhooks configurés dans le tableau de bord. Un événement de commentaire est livré à chaque webhook dont le domaine correspond, chacun sous forme de livraison distincte, quel que soit le mode de création du webhook.

Authentification

Chaque requête doit inclure votre clé API dans l’en-tête x-api-key (ou le paramètre de requête API_KEY) ainsi que votre ID de locataire dans le paramètre de requête tenantId. Les deux sont affichés sur la page API Secret du tableau de bord.

Souscrire

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"
}
ChampObligatoireDescription
urlYesUne URL http ou https absolue.
eventYescomment-created, comment-updated ou comment-deleted.
domainNoUn domaine provenant de la configuration de votre compte. La valeur par défaut est *, qui reçoit les événements pour tous les domaines.
methodNoPOST (par défaut), PUT ou DELETE.

La réponse contient l’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"
    }
}

S’abonner à la même URL pour le même événement et le même domaine renvoie à nouveau l’abonnement existant au lieu de créer un doublon, ce qui permet à un client de réessayer en toute sécurité. Chaque locataire peut avoir jusqu’à 50 abonnements API.

Lister

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

Renvoie tous les webhooks du locataire, y compris ceux gérés dans le tableau de bord ("source": "dashboard"). Filtrez avec event, domain ou source.

Se désabonner

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

Supprimer un abonnement supprime également tous les événements encore en file d’attente pour celui‑ci. Seuls les abonnements créés via l’API peuvent être supprimés de cette manière ; un webhook du tableau de bord, ou un identifiant qui n’existe pas sur votre compte, renvoie 404 avec le code not-found. Les webhooks du tableau de bord sont modifiés sur la page Webhooks.

Charges utiles et signature

Les livraisons utilisent la même charge utile que les webhooks du tableau de bord (voir Structures de données) et sont signées avec le même schéma HMAC (voir Sécurité & jetons API). Les abonnements API ne reçoivent jamais l’en‑tête hérité token, il faut donc vérifier l’en‑tête X-FastComments-Signature à la place.

Exemples de charges utiles

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

Renvoie les commentaires les plus récents du compte exactement dans la forme qu’une livraison transporte, afin qu’une intégration puisse afficher de vraies données d’exemple avant l’arrivée du premier événement. event est optionnel et uniquement validé, puisque chaque événement délivre le même objet commentaire. limit vaut par défaut 3 et accepte de 1 à 10. Coûte 2 crédits API.

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

Répondre avec 410 Gone

Si le point de terminaison d’un abonnement API répond avec HTTP 410 Gone, FastComments considère cela comme un désabonnement : l’abonnement est supprimé ainsi que ses événements en file d’attente, et aucune autre livraison n’est tentée. Les webhooks configurés dans le tableau de bord ne sont jamais supprimés automatiquement ; pour eux, un 410 représente simplement un échec. Tout autre statut d’échec est réessayé et finit par désactiver le webhook, comme décrit dans Fonctionnement & Gestion des nouvelles tentatives.

Tableau de bord

Les abonnements API apparaissent dans la liste des Webhooks avec la source API, où un administrateur peut les modifier, les désactiver, les réactiver ou les supprimer.


En conclusion

Cela conclut notre documentation sur les Webhooks.

Nous espérons que vous trouverez l'intégration Webhook de FastComments facile à comprendre et rapide à configurer.

Si vous pensez avoir identifié des lacunes dans notre documentation, faites-nous savoir ci-dessous.