Webhooks
Avise um sistema seu quando algo acontecer no Postline, com entregas assinadas e repetidas.
Os webhooks da organização chamam uma URL sua a cada evento escolhido, em qualquer projeto ou em um só. Cada entrega vai assinada, e uma entrega que falha é repetida.
Criar um endpoint
Em Organização › Webhooks, clique em Adicionar endpoint (donos e admins):
- A URL: só HTTPS, num endereço público. Endereços internos e de rede privada são recusados, ao salvar e a cada entrega.
- Os eventos (pelo menos um).
- O projeto, ou todos os projetos da organização.
O Postline gera uma chave de assinatura para o endpoint (whsec_…) e mostra uma vez. Guarde no seu sistema, por exemplo em POSTLINE_WEBHOOK_SECRET.
Eventos
O catálogo dos eventos da organização. Cada um tem a sua página na referência, com o data campo a campo e um exemplo.
| Evento | Quando |
|---|---|
article.published | Um artigo vai ao ar no destino principal (uma vez por revisão). |
article.review_requested | Um artigo fica pronto para revisão. |
article.scheduled | Alguém agenda um artigo ou muda a data. |
post.scheduled | Um destino de um post social ganha data e fica agendado. |
post.published | Um post social sai numa rede (uma vez por destino). |
delivery.failed | Uma publicação falha depois de todas as tentativas. |
credits.low | O uso de créditos do ciclo passa de 80% (data.percent). |
ping | Enviar evento de teste, só para aquele endpoint. |
Um site Next.js conectado recebe os seus próprios eventos, article.published, article.updated, article.unpublished, article.deleted e article.slug_changed, no mesmo envelope: veja Eventos do site.
O que enviamos
Todo evento que o Postline envia, aqui e para um site Next.js, tem o mesmo envelope e segue a especificação Standard Webhooks. Uma entrega é um POST com Content-Type: application/json:
POST /seu/endpoint HTTP/1.1
Content-Type: application/json
webhook-id: evt_4f1c2b7e9a0d4c3e8b6a5f2d1e0c9b8a
webhook-timestamp: 1760702400
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=| Campo | O que é |
|---|---|
id | O id do evento, evt_…. O mesmo em todas as tentativas e reenvios; igual ao webhook-id. |
type | O evento, do catálogo. |
version | A versão do envelope: 1. |
timestamp | Quando o evento aconteceu, ISO 8601 em UTC. |
organizationId | A organização. |
projectId | O projeto, ou null num evento da organização inteira (ping). |
data | O que é próprio do evento. |
O conteúdo do artigo nunca vai no evento: o seu sistema lê o que precisar pela API. Um evento completo (o data de cada um está no catálogo):
{
"id": "evt_4f1c2b7e9a0d4c3e8b6a5f2d1e0c9b8a",
"type": "article.published",
"version": 1,
"timestamp": "2026-10-17T12:00:00.000Z",
"organizationId": "Zx9…",
"projectId": "c3a8f2d0-…",
"data": {
"articleId": "0b9c4e7a-…",
"revision": 3,
"slug": "onboarding-que-segura-clientes",
"publicationId": "7d2e91c4-…"
}
}Responder e repetir
Responda com qualquer 2xx em até 10 segundos; o corpo da sua resposta é ignorado (guardamos os primeiros 500 caracteres para você ver no painel). Redirecionamentos não são seguidos.
Qualquer outra resposta, ou nenhuma, conta como falha, e a entrega é repetida com espera exponencial a partir de 30 segundos (30 s, 1 min, 2 min, 4 min…), até 12 tentativas, dentro de 24 horas.
- Idempotência: o
webhook-id(oiddo envelope) é o mesmo em todas as tentativas e reenvios de um evento. Guarde os ids que já processou e ignore repetidos; owebhook-timestampmuda a cada tentativa. - Ordem: entregas podem chegar fora de ordem. Use
timestampe leia o estado atual pela API quando a ordem importar. - Pausar: Pausar entregas segura o que acontecer enquanto isso; ao retomar, tudo é enviado.
- Reenviar: no painel do endpoint, Reenviar manda uma entrega de novo e Reenviar falhas manda todas as que não passaram.
Verificar a assinatura
O webhook-signature tem uma ou mais v1,<assinatura>, separadas por espaço. Cada uma é o HMAC-SHA256 em base64 de {webhook-id}.{webhook-timestamp}.{corpo}, o corpo cru, com a chave do endpoint. A chave é a parte do segredo depois de whsec_, decodificada de base64. Durante uma rotação vêm duas assinaturas, a da chave nova primeiro: aceite a entrega se qualquer uma bater. Recuse um webhook-timestamp com mais de 5 minutos de diferença do seu relógio, contra reenvios.
As bibliotecas oficiais do Standard Webhooks fazem tudo isso:
// npm install standardwebhooks
import { Webhook } from "standardwebhooks"
const webhook = new Webhook(process.env.POSTLINE_WEBHOOK_SECRET!) // "whsec_…"
// Um Route Handler do Next.js: leia o corpo como texto, antes de qualquer parse.
export async function POST(request: Request) {
const body = await request.text()
let event
try {
// Confere a assinatura e a janela de 5 minutos; devolve o envelope lido.
event = webhook.verify(body, Object.fromEntries(request.headers))
} catch {
return new Response("invalid signature", { status: 401 })
}
// … trate event.type, ignorando webhook-ids já vistos
return new Response(null, { status: 204 })
}Use o corpo cru
Calcule o HMAC sobre os bytes recebidos, antes de qualquer parse. Um JSON reformatado não bate com a assinatura.
Rotacionar a chave
No painel do endpoint, Rotacionar gera uma chave nova e mostra uma vez. A chave antiga continua assinando por 24 horas: nesse tempo o webhook-signature leva duas assinaturas, e o seu sistema aceita a entrega com qualquer uma das duas chaves.
- Clique em Rotacionar e copie a chave nova.
- Troque a chave no seu sistema e publique.
- Pronto. Depois de 24 horas a chave antiga para de assinar. Se o seu sistema já usa a nova, Revogar agora encerra a antiga na hora.
Se perder a chave, rotacione para gerar outra.
Testar
- Enviar evento de teste manda um evento
pingsó para aquele endpoint, assinado como os outros. - O painel do endpoint lista as últimas entregas, com o que foi enviado, a resposta, cada tentativa e a próxima.
- Em desenvolvimento, exponha o seu servidor local com um túnel HTTPS (por exemplo,
cloudflared tunnel --url http://localhost:3000) e use a URL pública dele como endpoint.