Documentation
Webhooks sortants : payload et signature
Recevez les alertes et les rapports d'AutoPSEO sous forme de JSON signé sur n'importe quel endpoint HTTPS : en-têtes de requête, champs du corps, types d'événements et vérification de la signature.
Un webhook sortant envoie les alertes, les rapports programmés, les messages de test et les résumés de rapport d'AutoPSEO vers un endpoint que vous hébergez, sous la forme d'un POST JSON par message, signé avec HMAC-SHA256. Utilisez-le pour alimenter Zapier, Make, n8n, un outil de gestion d'incidents ou votre propre code ; aucun compte Slack ou Teams n'est nécessaire. Vous cherchez le webhook qui livre des articles sur votre site ? Il relève du moteur de contenu : consultez la page livraison du contenu.
Ajouter un webhook
- Dans la section Webhooks sortants, cliquez sur Nouveau webhook.
- Donnez-lui un Nom et collez l'URL de l'endpoint. Elle doit être en HTTPS public : le simple
http,localhost, les noms se terminant par.localou.internal, les hôtes sans point et les adresses IP privées ou link-local sont refusés. - Copiez le secret de signature affiché après l'enregistrement. Il n'apparaît qu'une seule fois.
- Cliquez sur Envoyer un test pour poster un événement
test, puis rattachez des rapports programmés ou des alertes au webhook.
À quoi ressemble une requête de webhook
Chaque message est un POST accompagné de ces en-têtes :
| En-tête | Valeur |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1.0 |
X-AutoPSEO-Event | Le type d'événement, par exemple traffic_drop |
X-AutoPSEO-Signature | sha256= suivi de 64 caractères hexadécimaux en minuscules |
Voici une alerte de baisse de trafic pour une propriété de domaine, issue de l'exécution de 06:00 UTC le 12 octobre 2026, mise en forme pour la lecture (sur le réseau, il s'agit d'un JSON compact, et les valeurs id et site_id sont fictives) :
{
"id": "9b2e61f04c3a4d7e8f15a0b6c2d39e47",
"event_type": "traffic_drop",
"severity": "high",
"site_id": "4f0c1e9a2b7d4c58",
"site_url": "sc-domain:example.com",
"occurred_at": "2026-10-12T06:00:04.183Z",
"title": "Traffic drop: example.com",
"text": "Clicks 1,500 vs 2,000 in the previous window (-25.0%).",
"url": "https://app.autopseo.com/property/sc-domain%3Aexample.com",
"payload": {
"fields": [
{ "label": "Metric", "value": "clicks" },
{ "label": "Current", "value": "1,500" },
{ "label": "Baseline", "value": "2,000" },
{ "label": "Window", "value": "7 days (2026-10-05 → 2026-10-11 vs 2026-09-28 → 2026-10-04)" },
{ "label": "Change", "value": "-25.0%" }
],
"table": null,
"detector": "traffic_drop",
"window": 7,
"range": { "start": "2026-10-05", "end": "2026-10-11", "compStart": "2026-09-28", "compEnd": "2026-10-04" },
"result": {
"fired": true,
"metric": "clicks",
"value": 1500,
"baseline": 2000,
"change": -0.25,
"severity": "high",
"summary": "Clicks 1,500 vs 2,000 in the previous window (-25.0%)."
}
},
"source": "autopseo"
}
Les champs de premier niveau sont identiques pour tous les événements :
| Champ | Contenu |
|---|---|
id | Une chaîne hexadécimale aléatoire de 32 caractères, nouvelle à chaque requête |
event_type | Ce qui s'est produit (voir la section suivante) |
severity | critical, high, medium ou low pour les alertes ; info pour les rapports, les résumés et les tests |
site_id | L'identifiant AutoPSEO de la propriété, ou null pour les tests et la propriété de démonstration |
site_url | La propriété Search Console, par exemple sc-domain:example.com ou https://www.example.com/, ou null pour les tests |
occurred_at | Le moment de construction du message, sous forme d'horodatage ISO 8601 en UTC |
title, text | Le titre et la phrase de synthèse affichés par Slack et Teams |
url | Le rapport dans AutoPSEO, ou null pour les tests |
payload.fields | Les valeurs étiquetées que Slack affiche comme champs et Teams comme faits |
payload.table | columns et rows pour les rapports et les résumés, sinon null |
source | Toujours autopseo |
Les ratios sont des fractions : un change de -0.25 correspond à une baisse de 25 %, et un ctr de 0.034 à 3,4 %.
Types d'événements
event_type | Envoyé quand | Clés supplémentaires dans payload |
|---|---|---|
traffic_drop, traffic_spike, position_drop, ctr_drop, new_lost_rankings, anomaly, index_flip, rank_drop, audit_regression | Une règle d'alerte se déclenche, selon la planification ou via Tester la règle | detector, window, range (les dates, ou null pour index_flip, rank_drop et audit_regression), result |
scheduled_report | Un rapport programmé part, selon la planification ou via Envoyer maintenant | reportType (summary, queries, pages ou rankings), range (les dates plus un label), totals, previous |
report_summary | Quelqu'un utilise Envoyer vers Slack sur une page de rapport | Aucune : les chiffres figurent dans fields et table |
test | Quelqu'un clique sur Envoyer un test pour le webhook | sample, toujours à true |
result reprend ce que le détecteur a mesuré : fired, metric, value, baseline, change (null quand il n'y a rien à comparer), severity et summary, ainsi que z, le z-score modifié, pour anomaly. totals et previous contiennent clicks, impressions, ctr et position pour les deux fenêtres d'un rapport. Ce que mesure chaque détecteur est décrit dans la page Alertes.
Comment vérifier la signature
La signature est un HMAC-SHA256 des octets exacts envoyés par AutoPSEO, calculé avec le secret de signature du webhook et écrit sous la forme sha256= suivi de l'hexadécimal en minuscules. Pour la vérifier :
- Lisez le corps brut de la requête avant tout parsing JSON. Analyser puis resérialiser le contenu peut modifier les octets.
- Calculez le HMAC-SHA256 de ces octets, en utilisant le secret comme texte : la chaîne de 64 caractères telle qu'elle est affichée, sans la décoder depuis l'hexadécimal.
- Ajoutez le préfixe
sha256=et comparez le résultat à l'en-têteX-AutoPSEO-Signatureen temps constant. - Rejetez la requête si les valeurs diffèrent. Sinon, répondez immédiatement par un statut 2xx et effectuez le traitement lent ensuite.
Un récepteur pour Node.js, sans aucune dépendance :
import { createServer } from 'node:http';
import { createHmac, timingSafeEqual } from 'node:crypto';
const secret = process.env.AUTOPSEO_WEBHOOK_SECRET;
createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const raw = Buffer.concat(chunks);
const expected = Buffer.from('sha256=' + createHmac('sha256', secret).update(raw).digest('hex'));
const received = Buffer.from(String(req.headers['x-autopseo-signature'] || ''));
if (received.length !== expected.length || !timingSafeEqual(received, expected)) {
res.writeHead(401).end();
return;
}
res.writeHead(204).end();
const event = JSON.parse(raw.toString('utf8'));
console.log(event.event_type, event.severity, event.site_url);
});
}).listen(8080);
La vérification de la longueur passe en premier, car la fonction timingSafeEqual de Node lève une exception lorsque les deux buffers n'ont pas la même longueur.
Règles de livraison
- Chaque message fait l'objet d'une seule tentative, avec un délai d'expiration de 10 secondes. Toute réponse autre que 2xx est considérée comme un échec et est conservée dans l'Historique des envois avec le code de statut et le début du corps de votre réponse.
- Les redirections ne sont pas suivies. Une réponse 3xx échoue avec une note invitant à utiliser l'URL finale.
- Aucun nouvel essai n'est programmé. Une alerte en échec n'est pas marquée comme envoyée : à la vérification suivante, elle est réévaluée et publiée si elle se déclenche toujours, le lendemain matin pour la plupart des détecteurs, l'heure suivante pour les index flips. Un rapport programmé en échec n'est pas renvoyé au cours de la même période : utilisez Envoyer maintenant une fois l'endpoint corrigé.
idest créé à chaque requête ; il identifie donc un envoi et non un événement. Pour dédupliquer les alertes, combinezevent_type,site_urlet la date deoccurred_at: une règle publie au plus une fois par propriété et par jour UTC, sauf si quelqu'un lance Tester la règle.
Le secret de signature
AutoPSEO n'affiche le secret de signature qu'une seule fois, à l'enregistrement du webhook, et la liste ne le montre plus jamais ensuite. Conservez-le immédiatement dans la configuration de votre récepteur, à côté de l'endpoint qu'il protège.
L'URL elle-même est stockée chiffrée, et la liste n'en montre que l'hôte et les derniers caractères. Supprimer un webhook supprime aussi toutes les règles qui publient vers lui. Pour obtenir une carte lisible dans un canal Teams plutôt que du JSON, utilisez Microsoft Teams.