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):

  1. 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.
  2. Os eventos (pelo menos um).
  3. 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.

EventoQuando
article.publishedUm artigo vai ao ar no destino principal (uma vez por revisão).
article.review_requestedUm artigo fica pronto para revisão.
article.scheduledAlguém agenda um artigo ou muda a data.
post.scheduledUm destino de um post social ganha data e fica agendado.
post.publishedUm post social sai numa rede (uma vez por destino).
delivery.failedUma publicação falha depois de todas as tentativas.
credits.lowO uso de créditos do ciclo passa de 80% (data.percent).
pingEnviar 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=
CampoO que é
idO id do evento, evt_…. O mesmo em todas as tentativas e reenvios; igual ao webhook-id.
typeO evento, do catálogo.
versionA versão do envelope: 1.
timestampQuando o evento aconteceu, ISO 8601 em UTC.
organizationIdA organização.
projectIdO projeto, ou null num evento da organização inteira (ping).
dataO 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 (o id do envelope) é o mesmo em todas as tentativas e reenvios de um evento. Guarde os ids que já processou e ignore repetidos; o webhook-timestamp muda a cada tentativa.
  • Ordem: entregas podem chegar fora de ordem. Use timestamp e 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.

  1. Clique em Rotacionar e copie a chave nova.
  2. Troque a chave no seu sistema e publique.
  3. 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 ping só 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.

Nesta página