Documentação
Webhooks de saída: payload e assinatura
Receba alertas e relatórios do AutoPSEO como JSON assinado em qualquer endpoint HTTPS: os cabeçalhos da requisição, os campos do corpo, os tipos de evento e como verificar a assinatura.
Um webhook de saída envia os alertas, os relatórios agendados, as mensagens de teste e os resumos de relatórios do AutoPSEO para um endpoint que você mantém, como um POST JSON por mensagem, assinado com HMAC-SHA256. Use-o para alimentar Zapier, Make, n8n, uma ferramenta de incidentes ou o seu próprio código; não é necessária nenhuma conta do Slack ou do Teams. Procura o webhook que entrega artigos ao seu site? Esse pertence ao mecanismo de conteúdo: veja entrega de conteúdo.
Adicionar um webhook
- Na seção Outbound webhooks, clique em New webhook.
- Dê um Name ao webhook e cole a URL do endpoint. Ela deve ser HTTPS público:
httpsimples,localhost, nomes terminados em.localou.internal, hosts sem ponto e endereços IP privados ou link-local são recusados. - Copie o signing secret exibido depois de salvar. Ele é mostrado apenas desta vez.
- Clique em Send test para enviar um evento
teste, em seguida, associe ao webhook os relatórios agendados ou os alertas.
Como é uma requisição de webhook
Toda mensagem é um POST com estes cabeçalhos:
| Cabeçalho | Valor |
|---|---|
Content-Type | application/json |
User-Agent | AutoPSEO-Webhook/1.0 |
X-AutoPSEO-Event | O tipo de evento, por exemplo traffic_drop |
X-AutoPSEO-Signature | sha256= seguido de 64 caracteres hexadecimais em minúsculas |
Veja um alerta de queda de tráfego para uma propriedade de domínio, da execução das 06:00 UTC de 12 de outubro de 2026, formatado para leitura (na transmissão real, o JSON é compacto, e os valores de id e site_id são fictícios):
{
"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"
}
Os campos de nível superior são os mesmos em todos os eventos:
| Campo | O que contém |
|---|---|
id | Uma string hexadecimal aleatória de 32 caracteres, nova a cada requisição |
event_type | O que aconteceu (veja a próxima seção) |
severity | critical, high, medium ou low para alertas; info para relatórios, resumos e testes |
site_id | O id da propriedade no AutoPSEO, ou null para testes e para a propriedade de demonstração |
site_url | A propriedade do Search Console, como sc-domain:example.com ou https://www.example.com/, ou null para testes |
occurred_at | Quando a mensagem foi montada, como um timestamp ISO 8601 em UTC |
title, text | O título e a frase de resumo que o Slack e o Teams exibem |
url | O relatório no AutoPSEO, ou null para testes |
payload.fields | Os valores rotulados que o Slack exibe como campos e o Teams como fatos |
payload.table | columns e rows para relatórios e resumos; caso contrário, null |
source | Sempre autopseo |
As razões são frações: um change de -0.25 é uma queda de 25%, e um ctr de 0.034 é 3,4%.
Tipos de evento
event_type | Enviado quando | Chaves extras em payload |
|---|---|---|
traffic_drop, traffic_spike, position_drop, ctr_drop, new_lost_rankings, anomaly, index_flip, rank_drop, audit_regression | Uma regra de alerta dispara, no agendamento ou por meio de Test rule | detector, window, range (as datas, ou null para index_flip, rank_drop e audit_regression), result |
scheduled_report | Um relatório agendado é enviado, no agendamento ou por meio de Send now | reportType (summary, queries, pages ou rankings), range (datas mais um label), totals, previous |
report_summary | Alguém usa Send to Slack na página de um relatório | Nenhuma: os números estão em fields e table |
test | Alguém clica em Send test no webhook | sample, sempre true |
result repete o que o detector mediu: fired, metric, value, baseline, change (null quando não há com o que comparar), severity e summary, além de z, o z-score modificado, no caso de anomaly. totals e previous contêm clicks, impressions, ctr e position das duas janelas de um relatório. O que cada detector mede está descrito em Alertas.
Como verificar a assinatura
A assinatura é um HMAC-SHA256 dos bytes exatos enviados pelo AutoPSEO, calculado com o signing secret do webhook como chave e escrito como sha256= mais hexadecimal em minúsculas. Para verificá-la:
- Leia o corpo bruto da requisição antes de qualquer parsing de JSON. Fazer o parsing e serializar de novo pode alterar os bytes.
- Calcule o HMAC-SHA256 desses bytes, usando o secret como texto: a string de 64 caracteres exatamente como é exibida, sem decodificá-la de hexadecimal.
- Adicione o prefixo
sha256=e compare o resultado com o cabeçalhoX-AutoPSEO-Signatureem tempo constante. - Rejeite a requisição se forem diferentes. Caso contrário, responda imediatamente com um status 2xx e faça o trabalho mais demorado depois.
Um receptor para Node.js sem dependências:
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);
A verificação de tamanho vem primeiro porque o timingSafeEqual do Node lança uma exceção quando os dois buffers têm tamanhos diferentes.
Regras de entrega
- Cada mensagem recebe uma única tentativa, com timeout de 10 segundos. Qualquer resposta diferente de 2xx conta como falha e fica registrada no Delivery history com o código de status e o início do corpo da resposta.
- Redirecionamentos não são seguidos. Uma resposta 3xx falha com uma observação para usar a URL final.
- Nada é reenviado por temporizador. Um alerta com falha não é marcado como enviado, então a próxima verificação o avalia de novo e o publica se ele ainda disparar: na manhã seguinte para a maioria dos detectores, na hora seguinte para as mudanças de indexação. Um relatório agendado com falha não é reenviado no mesmo período; use Send now depois de corrigir o endpoint.
- O
idé criado a cada requisição, portanto identifica uma entrega, e não um evento. Para eliminar duplicatas de alertas, combineevent_type,site_urle a data deoccurred_at: uma regra publica no máximo uma vez por propriedade por dia UTC, a menos que alguém execute Test rule.
O signing secret
O AutoPSEO mostra o signing secret uma única vez, quando você salva o webhook, e a lista nunca o exibe novamente. Guarde-o de imediato na configuração do seu receptor, junto ao endpoint que ele protege.
A própria URL é armazenada criptografada, e a lista mostra apenas o host e os últimos caracteres. Excluir um webhook também exclui todas as regras que publicam nele. Para um cartão legível em um canal do Teams, em vez de JSON, use o Microsoft Teams.