Blog

Arrêtez d'interroger notre API en boucle pour détecter un changement de score — utilisez le webhook

Si vous vérifiez /api/v1/visibility sur une minuterie, vous résolvez un problème de push avec un outil de pull. Voici exactement comment fonctionne le webhook sortant de PingMyBrand — le vrai payload, le vrai calendrier de nouvelles tentatives, et un exemple concret qui relaie une baisse de score directement dans Slack.

L'équipe PingMyBrand5 min de lectureRead in English
Sur cette page
  1. 01Pourquoi c'est un problème de push, pas de pull
  2. 02Ce qui se déclenche réellement, et quand
  3. 03Vérifiez-le, ou ne lui faites pas confiance
  4. 04Un exemple concret : relayer une vraie baisse dans Slack
  5. 05Ce que "retenté" veut dire concrètement pour votre récepteur
  6. 06Récupérez la clé, câblez l'URL, terminé

Si votre intégration interroge l'API de visibilité en lecture seule sur une tâche planifiée pour détecter un changement de score, vous résolvez un problème de push avec un outil de pull — vous brûlez votre budget de limite de débit à demander "est-ce que quelque chose a changé ?" des dizaines de fois pour chaque fois où la réponse est vraiment oui. La solution, c'est le webhook, pas un intervalle d'interrogation plus serré : enregistrez une URL, et nous y envoyons un POST — signé HMAC, retenté, documenté — au moment exact où une marque suivie par votre compte a un vrai changement de score non nul. Ce billet est le détail mécanique que la référence API énonce sans s'y attarder : pourquoi le push bat le pull précisément ici, et un exemple concret qui branche un résultat de scan directement dans Slack.

Pourquoi c'est un problème de push, pas de pull

Un score de visibilité ne change pas sur votre calendrier — il change quand nous terminons un re-scan hebdomadaire, ou quand vous en déclenchez un manuel, ce qui arrive sur notre horloge, pas sur un intervalle fixe que vous pouvez prédire. Interroger pour ça revient à choisir un intervalle soit trop lent (vous découvrez une vraie baisse des heures après, pendant qu'un client ou votre propre équipe l'a déjà remarquée sur Twitter), soit gaspilleur (vérifier toutes les quelques minutes un événement qui arrive, au maximum, une fois par semaine par marque). Un webhook contourne complètement la devinette : rien n'arrive tant que quelque chose n'a pas vraiment changé, et ça arrive en quelques secondes après le changement plutôt qu'au début de votre prochaine fenêtre d'interrogation.

Ce qui se déclenche réellement, et quand

Enregistrez une URL de rappel avec un POST vers /api/v1/webhooks (authentification par clé porteur, la même clé que l'API REST) et vous obtenez exactement un enregistrement actif par compte — enregistrer à nouveau fait tourner la clé, remplaçant purement et simplement l'ancienne URL et le secret, donc désactivez tout consommateur de l'ancienne URL avant de tourner la clé, pas après. La livraison ne se déclenche que sur scan_completed avec un vrai delta de score non nul — un score inchangé après un re-scan ne déclenche jamais rien, et il n'y a aucun moyen de déclencher une livraison de test à partir d'un scan qui n'a pas vraiment bougé. Ce dernier point est délibéré : un webhook qui se déclenche sur demande ne vous dirait rien sur s'il est bien câblé pour le cas qui compte vraiment.

Le payload est volontairement petit et plat : domain, slug, le nouveau score, le previousScore, le delta calculé, une ventilation par moteur, et un horodatage. Assez pour poster un message Slack utile ou mettre à jour une cellule de tableau de bord sans appel API de suivi — même si le domaine et le slug sont là précisément pour que vous puissiez appeler /api/v1/visibility pour le détail complet par moteur si votre cas d'usage en a besoin.

Vérifiez-le, ou ne lui faites pas confiance

Chaque livraison porte un en-tête X-PingMyBrand-Signature: sha256=... — un HMAC-SHA256 du corps brut de la requête, signé avec le secret qui vous a été montré exactement une fois à l'enregistrement. Recalculez-le vous-même avant d'agir sur un payload :

import crypto from "crypto";

function verify(secret, rawBody, header) {
  const [, sig] = header.split("=");
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"));
}

Sautez cette étape et votre endpoint n'est qu'une URL publique non authentifiée qui reçoit du JSON — n'importe qui qui la trouve peut poster un faux payload "score tombé à 0" et regarder votre équipe paniquer pour rien.

Un exemple concret : relayer une vraie baisse dans Slack

Voici la forme d'un récepteur minimal — vérifier, contrôler le signe du delta, ne relayer que le cas qu'un humain a vraiment besoin de voir :

app.post("/pingmybrand-hook", express.raw({ type: "*/*" }), async (req, res) => {
  const sig = req.headers["x-pingmybrand-signature"];
  if (!verify(process.env.PMB_WEBHOOK_SECRET, req.body, sig)) {
    return res.status(401).end();
  }
  const event = JSON.parse(req.body);
  res.status(200).end(); // accuser réception immédiatement — appeler Slack ensuite

  if (event.delta < 0) {
    await postToSlack(
      `⚠️ La visibilité IA de ${event.domain} a chuté de ${Math.abs(event.delta)} points (maintenant ${event.score}/100)`
    );
  }
});

Deux choses dans cet extrait sont structurantes, pas stylistiques. D'abord, accusez réception de la requête avant de faire un travail lent — répondez 200 immédiatement, puis appelez Slack ; un récepteur qui nous fait attendre sur une API tierce risque de dépasser notre délai de livraison de 10 secondes et de déclencher une nouvelle tentative pour une livraison que vous avez en réalité déjà reçue. Ensuite, filtrez vous-même sur le signe du delta — chaque vrai changement est livré, hausses comprises, donc si vous ne vous souciez que des régressions, c'est un if d'une ligne, pas un réglage que nous exposons.

Ce que "retenté" veut dire concrètement pour votre récepteur

Une livraison échouée — une réponse non-2xx, un délai dépassé après 10 secondes, ou une erreur réseau — est retentée jusqu'à 4 tentatives au total, en attendant 0,5 s, puis 1 s, puis 2 s entre elles (le même calendrier que la référence API documente). Une exécution compte comme réussie dès qu'une tentative reçoit un 2xx en retour ; à l'instant où votre récepteur accuse réception, les nouvelles tentatives s'arrêtent. Concevez votre endpoint pour qu'il soit reposté sans risque : si votre récepteur plante en cours de traitement après avoir accepté une requête mais avant de l'avoir enregistrée en interne, une nouvelle tentative pour le même événement arrivera simplement de nouveau avec le même payload. Dédupliquer sur domain + timestamp avant d'agir sur une livraison est une protection de cinq minutes contre un double post dans Slack si ça arrive un jour.

Récupérez la clé, câblez l'URL, terminé

Les webhooks sont actifs sur chaque plan payant — pas de module complémentaire séparé, la même clé porteuse que vous mintez pour l'API REST. Créez-en une depuis votre page de compte, enregistrez votre URL avec l'exemple curl sur la référence développeur, et le prochain vrai changement de score — le vôtre ou celui d'un client, si vous suivez plusieurs marques — atterrit dans votre propre système en quelques secondes, signé, au lieu d'attendre votre prochaine interrogation pour vous en apercevoir.

L'IA vous recommande, ou un concurrent ?

Entrez votre domaine. Nous posons 25 vraies questions d'acheteur à ChatGPT, Claude, Gemini et Perplexity et vous montrons, par question, si vous êtes nommé — la phrase exacte, pas un simple voyant vert. Gratuit, sans inscription, en une minute environ.

Gratuit · sans inscription · 4 moteurs · ~60 secondes

À lire aussi