Webhooks
Só de saída. O Opini faz um POST com um corpo JSON numa URL sua sempre que algo importante acontece: um item do roadmap? é entregue, um comentário fica pendente, um lançamento é publicado, uma pergunta de acompanhamento é respondida. Cole a URL de um webhook do Discord e as mensagens chegam no seu canal sem nenhum código.
O que são
Três pedidos comuns que os webhooks resolvem direto:
- "Avise meu canal do Discord quando um comentário novo esperar aprovação."
- "Dispare meu pipeline de deploy quando publicarmos um lançamento."
- "Avise o canal do suporte quando uma pergunta for respondida."
Todos usam a mesma base: Opini, chame esta URL quando X acontecer, com um JSON que eu consiga ler. Webhooks são por projeto, no máximo 10 por projeto.
Criar um
Abra Configurações → Webhooks no painel. Preencha:
- URL:
https://ouhttp://(mas, por favor,https://). Sem usuário e senha na URL. - Nome: algo legível, como ops-discord ou pipeline-deploy. Aparece na lista de webhooks e no histórico de entregas.
- Eventos: marque os tipos que quiser, agrupados por item (comentários, itens do roadmap, lançamentos, perguntas, feedback).
- Compatível com Discord: ative se a URL for um webhook de canal do Discord. Veja abaixo.
- Segredo de assinatura: (opcional) gere um para assinar as requisições com HMAC-SHA256. Mostrado uma vez na criação; gere outro se perder.
Um botão Enviar evento de teste em cada linha dispara um evento de exemplo na URL, para confirmar que ela responde antes de depender dela.
Eventos
Lista inicial; tipos desconhecidos recebem um 422 na criação:
| Tipo | Dispara quando |
|---|---|
| comment.pending | Um comentário novo aguarda moderação. |
| comment.approved | Um admin aprova um comentário. |
| comment.rejected | Um comentário é rejeitado. |
| umbrella.created | Um item do roadmap é criado (rascunho ou publicado). |
| umbrella.moved | Um item do roadmap muda de coluna de status. |
| umbrella.shipped | A coluna de destino é de 'entregue' ou 'feito'. Dispara além de umbrella.moved. |
| umbrella.published | Um item do roadmap fica público pela primeira vez (aparece na API pública do roadmap). |
| umbrella.unpublished | Um item do roadmap sai do roadmap público. |
| release.published | Um lançamento é publicado. |
| release.unpublished | Um lançamento sai do ar. |
| follow_up.asked | Um admin envia uma pergunta de acompanhamento. |
| follow_up.answered | A pessoa responde a uma pergunta de acompanhamento. |
| feedback.received | Um feedback novo chega na triagem (widget ou API). |
Os webhooks só veem eventos que acontecem depois de serem criados, sem retroativo. É de propósito: repetir meses de mudanças para uma URL recém-inscrita quase nunca é o que alguém quer.
Formato do conteúdo
O modo bruto é o padrão. Toda requisição tem o mesmo envelope; o objeto data depende do tipo de evento.
{
"event_id": "01JSAE...",
"event_kind": "comment.pending",
"occurred_at": "2026-04-24T07:03:11Z",
"project": { "id": "prj_...", "slug": "acme" },
"entity": {
"kind": "comment",
"id": "cmt_...",
"url": "https://opini.dev/app/orgs/<org>/projects/<project>/moderation"
},
"data": {
"body": "This is the comment body...",
"umbrella_id": "umb_...",
"umbrella_title": "Dark mode",
"author_name": "anon-dolphin"
}
}Modo compatível com Discord
Ative Compatível com Discord e o conteúdo vira {content, embeds}, o formato que a API de webhooks do Discord espera. Sem nenhum intermediário.
{
"content": "New comment pending approval on **Dark mode**",
"embeds": [{
"title": "Dark mode",
"description": "This is the comment body, truncated to 300 chars...",
"url": "https://opini.dev/app/orgs/<org>/projects/<project>/moderation",
"color": 16730759
}]
}As cores variam por tipo: comentários pendentes em âmbar, aprovações em verde, itens entregues em violeta, o resto no azul da marca. As descrições vão até 300 caracteres (o Discord aceita 4096, mas ficamos no curto para o embed continuar fácil de ler).
Assinatura e cabeçalhos
Se você configurar um segredo de assinatura, toda requisição leva:
X-Opini-Signature: sha256=<hex>: HMAC-SHA256 do corpo bruto, com o segredo como chave.X-Opini-Event: <event_kind>: o tipo do evento, para rotear rápido.X-Opini-Delivery: <delivery_id>: um id único por tentativa de entrega. Use para ignorar repetições no destino.
O Discord não verifica esses cabeçalhos, então eles não atrapalham num webhook compatível com Discord. Gerar um novo segredo cria outro valor; o antigo para de valer na hora.
Histórico de entregas
Clique numa linha de webhook e um painel lateral mostra as últimas 100 tentativas de entrega. Cada linha mostra o tipo de evento, um status (2xx verde, 4xx âmbar, 5xx ou erro de rede vermelho), a duração e há quanto tempo foi. Ao expandir, você vê o resumo da requisição e da resposta.
Tentativas além das 100 mais recentes são apagadas automaticamente: isto não é um log de auditoria completo, é um "o que aconteceu nas últimas horas".
Tentativas e limites
- 3 tentativas, com espera exponencial. 1s → 4s → 16s. Depois da terceira, o Opini registra a falha e segue em frente.
- Tempo limite de 5 segundos por requisição. Um endpoint lento conta como falha.
- 10 webhooks por projeto. Se precisar de mais, junte: a maioria dos times acaba com chat, pipeline e um endpoint de debug.
- Webhooks desativados são pulados. Desative um webhook em vez de apagar enquanto investiga: o histórico de entregas fica.
Webhooks disparam em mudanças de comentários, itens do roadmap, lançamentos e perguntas de acompanhamento.