Webhooks

Um webhook de entrada permite que outro sistema publique em um canal enviando JSON para uma URL secreta. Um webhook de saída faz o oposto: ele envia mensagens para a sua URL, aquelas que começam com uma palavra gatilho ou que as pessoas escolhem no menu de mensagem, e publica o que você responde.

Onde gerenciar webhooks

Abra seu avatar no canto superior direito e depois Integrações. As páginas de integrações da comunidade atual listam Webhooks Entrada e Webhooks Saída. Cada webhook pertence a uma comunidade.

Por padrão, administradores de comunidade e administradores do sistema podem criar webhooks. Um administrador do sistema pode conceder esse direito a outros papéis nas configurações de permissões do Console do Sistema. Um administrador do sistema também pode desativar cada tipo em Console do Sistema › Integrações › Gerenciamento de Integração: Ativar Webhooks Entrada e Ativar Webhooks Saída estão ambos ativados por padrão.

A channel with messages from a CI bot and from GitHub, shown as cards with fields, pipeline stages and a button
Mensagens de integração desenhadas como cartões: campos, etapas do pipeline e um botão de ação.

Criar um webhook de entrada

  1. Em Integrações, escolha Webhooks Entrada e depois Adicionar Webhooks Entrada.
  2. Preencha um Título e uma Descrição: eles aparecem apenas nas páginas de integrações.
  3. Escolha o Canal para onde as mensagens vão por padrão. Para um Canal Privado, você deve ser membro dele.
  4. Marque Travar neste canal se os remetentes não devem poder publicar em outros lugares.
  5. Opcionalmente, defina uma URL para Usuário e Imagem do Perfil para suas mensagens (veja Nome e ícone).
  6. Escolha Salvar. Copie a URL exibida: https://chat.example.com/hooks/<key>.
A URL é o único segredo: qualquer pessoa que a tenha pode publicar no canal. Mantenha-a fora de repositórios públicos e exclua o webhook se ela vazar.

Com a API: POST /api/v4/hooks/incoming com {"channel_id", "display_name", "description", "username", "icon_url", "channel_locked"}; o id da resposta é a chave. Da linha de comando: amctl webhook create-incoming --channel <channel id> --user <user> --display-name "CI".

Enviar uma mensagem para um webhook de entrada

curl -X POST https://chat.example.com/hooks/xgh5ycrx1jf7mbs9w8z4c8e7ho \
  -H 'Content-Type: application/json' \
  -d '{"text": "Deploy of **api 2.4.0** finished :white_check_mark:"}'

O servidor responde 200 com o corpo ok. Ele também aceita application/x-www-form-urlencoded com o JSON em um campo payload, como os webhooks do Slack, então as ferramentas feitas para o Slack geralmente funcionam sem alterações.

CampoSignificado
textA mensagem, em Markdown. Obrigatório, a menos que haja attachments. Um texto mais longo que o limite de mensagem do servidor é dividido em várias mensagens.
channelOutro canal da comunidade do webhook, pelo nome (ops-alerts ou #ops-alerts), ou @username para uma mensagem direta do proprietário do webhook. Recusado quando o webhook está bloqueado para o seu canal. O nome antigo town-square ainda alcança o canal padrão da comunidade, agora chamado general.
username, icon_url, icon_emojiO nome e a imagem a exibir, quando o servidor permite substituições.
attachmentsAnexos da mensagem, exibidos como cartões (abaixo).
propsPropriedades extras armazenadas na mensagem, para aplicativos que as leem.
typeUm tipo de mensagem personalizado, como custom_poll, para um aplicativo que o exibe. Tipos que começam com system_ são recusados.
root_idO ID da primeira mensagem de um tópico, para responder nesse tópico.
priorityPrioridade da mensagem, por exemplo {"priority": "urgent"}.
silenttrue envia a mensagem sem notificações push.

Toda mensagem publicada por um webhook carrega uma tag BOT ao lado do seu nome, mesmo quando exibida sob o nome do seu criador, para que as pessoas possam diferenciá-la de uma mensagem de uma pessoa real. Mensagens de webhook nunca acionam webhooks de saída.

Nome e ícone

Um webhook publica como a pessoa que o criou, a menos que o servidor permita substituições. Duas configurações em Console do Sistema › Integrações › Gerenciamento de Integração, ambas desativadas por padrão, mudam isso:

  • Permitir que integrações sobrescrevam o nome do usuário (ServiceSettings.EnablePostUsernameOverride): o Usuário do webhook ou o username da solicitação é exibido; sem nenhum dos dois, o nome é webhook.
  • Permitir que integrações sobrescreva o imagem do perfil (ServiceSettings.EnablePostIconOverride): a Imagem do Perfil do webhook, ou o icon_url ou icon_emoji da solicitação, é exibido.

Um valor na solicitação tem prioridade sobre o valor salvo no webhook.

Anexos

Anexos adicionam conteúdo estruturado abaixo do texto. Eles seguem o formato de anexo de mensagem do Slack:

{
  "text": "Build failed on `main`",
  "attachments": [{
    "fallback": "main #1902 failed",
    "color": "#d24b4e",
    "author_name": "GitHub Actions",
    "author_icon": "https://chat.example.com/static/ci.png",
    "title": "main #1902 failed",
    "title_link": "https://ci.example.com/runs/1902",
    "text": "Commit `0f4d8e2` by Jonas Weber",
    "fields": [
      {"title": "Branch", "value": "zephyr-3.7", "short": true},
      {"title": "Duration", "value": "3m 40s", "short": true}
    ],
    "footer": "Lumen CI",
    "ts": 1760000000
  }]
}
CampoSignificado
fallbackTexto simples para locais que não podem exibir o cartão, como notificações.
colorA barra de cor: uma cor hexadecimal, ou good, warning, danger.
pretextTexto acima do cartão.
author_name, author_link, author_iconUma linha de cabeçalho pequena.
title, title_linkO título do cartão, opcionalmente um link.
textO corpo do cartão, em Markdown.
fieldsUma lista de {"title", "value", "short"}; campos short ficam lado a lado.
image_url, thumb_urlUma imagem grande abaixo, ou uma pequena ao lado.
footer, footer_icon, tsUma linha de rodapé e um tempo (segundos Unix).
actionsBotões e menus: veja Mensagens interativas.

Cartões: etapas e gráficos

O Antimatter adiciona dois campos aos anexos, exibidos pela interface padrão:

  • stages: as etapas de um pipeline, exibidas como pílulas, até 20. Cada uma é {"name", "status"}, com status passed, failed, running, pending, skipped ou canceled.
  • chart: um pequeno gráfico de linha de valores recentes, {"values": [2 to 200 numbers], "threshold": number, "label": "…"}. O limite é desenhado como uma linha tracejada, para o limite de um alerta.
{
  "attachments": [{
    "color": "danger",
    "title": "main #1902 failed",
    "stages": [
      {"name": "build", "status": "failed"},
      {"name": "unit", "status": "skipped"},
      {"name": "publish", "status": "skipped"}
    ]
  }, {
    "color": "warning",
    "title": "API latency above 400 ms",
    "chart": {"values": [210, 230, 260, 390, 450, 470], "threshold": 400, "label": "p95 latency, ms"}
  }]
}

A interface clássica e outros clientes ignoram esses dois campos, então inclua também as informações essenciais em text ou fields.

Criar um webhook de saída

Um webhook de saída monitora os canais Público de uma comunidade. Ele envia uma mensagem para a sua URL quando a primeira palavra da mensagem corresponde a uma de suas palavras gatilho, ou quando alguém o seleciona no menu da mensagem (uma ação de mensagem).

  1. Em Integrações, escolha Webhooks Saída e depois Adicionar Webhooks Saída.
  2. Preencha o Título e a Descrição.
  3. Escolha o Tipo de Conteúdo (Content Type) da solicitação: application/x-www-form-urlencoded ou application/json.
  4. Escolha um Canal, insira Palavras Gatilho (Uma Por Linha), ou ambos. Com um canal e sem palavras gatilho, todas as mensagens desse canal são enviadas. Com ambos, a mensagem deve corresponder a ambos.
  5. Em Enviar quando, escolha Primeira palavra deve corresponder exatamente a uma palavra gatilho, Primeira palavra começa com uma palavra gatilho ou Do menu de mensagem. Com Do menu de mensagem, as palavras gatilho desaparecem, o Canal é opcional (sem ele, a ação é oferecida em todos os canais públicos da comunidade) e o Título é obrigatório: é o nome da ação no menu.
  6. Insira as URLs Callback (Uma Por Linha). Cada URL recebe todas as mensagens correspondentes.
  7. Opcionalmente, defina o Usuário e a Imagem do Perfil usados para as respostas. Para uma ação do menu de mensagem, o campo Ícone substitui Imagem do Perfil: a URL de uma imagem .png ou .jpg ou, na interface padrão do Antimatter, uma imagem enviada. O menu a exibe em cinza; sem uma, a ação recebe um ícone neutro.
  8. Escolha Salvar e copie o token exibido. Seu serviço o usa para verificar se as solicitações vêm do seu servidor.

Com a API: POST /api/v4/hooks/outgoing com {"team_id", "channel_id", "trigger_words", "trigger_when", "callback_urls", "content_type", "display_name"} (trigger_when: 0 para correspondência exata, 1 para "começa com", 2 para "do menu da mensagem"). Um webhook com trigger_when 2 não usa palavras de gatilho e requer um display_name. Envie seu ícone com POST /api/v4/hooks/outgoing/{hook_id}/icon (multipart, campo image: PNG, JPEG ou GIF, armazenado como PNG de 128 px); seu icon_url então aponta para GET /api/v4/hooks/outgoing/{hook_id}/icon.

Se o seu serviço estiver em uma rede privada, um administrador do sistema deve permitir seu endereço em Permitir conexão interna não confiável (ServiceSettings.AllowedUntrustedInternalConnections). Caso contrário, o servidor não chama endereços privados.

A solicitação de saída

O Antimatter envia um POST com esses campos, como JSON ou form-encoded, dependendo do tipo de conteúdo:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "text": "deploy api 2.4.0",
  "trigger_word": "deploy",
  "file_ids": ""
}

Compare token com o token do webhook antes de fazer qualquer coisa. Na versão codificada em formulário, timestamp está em segundos, não em milissegundos. O servidor aguarda sua resposta pelo tempo permitido por Tempo limite de solicitação de integração (30 segundos por padrão, ServiceSettings.OutgoingIntegrationRequestsTimeout).

Responder a um webhook de saída

Para publicar uma resposta, responda com JSON. Para não publicar nada, responda com um corpo vazio.

{
  "text": "Deploying **api 2.4.0** to staging…",
  "response_type": "comment",
  "username": "deploy-bot",
  "icon_url": "https://chat.example.com/static/deploy.png"
}
  • text e attachments: a resposta. Sem nenhum dos dois, nada é publicado.
  • response_type: comment publica a resposta no tópico da mensagem que disparou; caso contrário, vai para o canal.
  • username, icon_url: exibidos quando o servidor permite substituições; caso contrário, são usados os próprios valores do webhook.
  • props, type, priority: como nos webhooks de entrada.

A resposta é publicada como o criador do webhook, sob o nome substituído, quando houver. Para qualquer coisa mais longa do que uma resposta rápida, responda imediatamente e publique depois com um webhook de entrada ou a API.

Ações de mensagem

Uma ação de mensagem é um webhook de saída com Enviar quando definido como Do menu da mensagem. Ela nunca é acionada por mensagens publicadas. Em vez disso, as pessoas a veem no menu de uma mensagem: Ações de mensagem (⋯) › Ações, sob o título Integrações, com seu ícone. A interface clássica não exibe ações de mensagem. Ao selecioná-la, aquela mensagem é enviada para as URLs de callback, e uma breve notificação indica Enviado para o nome da ação, ou exibe seu ephemeral_text.

  • Onde aparece: no canal do webhook ou, sem um canal, em todos os canais públicos de sua comunidade. Apenas canais públicos têm ações de mensagem.
  • Convidados só recebem as ações vinculadas a um canal em que estão, não as de toda a comunidade.
  • Canais arquivados e somente leitura: a mensagem ainda pode ser enviada. Arquivar um canal exclui os webhooks vinculados a ele, portanto um canal arquivado mantém apenas as ações de toda a comunidade. Uma resposta que a pessoa não pôde publicar lá é mostrada apenas a ela.
  • Limite de taxa: cada pessoa pode executar 10 ações de mensagem por minuto, após um pico de 5. Acima disso, o servidor responde 429.
  • Redes privadas: como para outros webhooks de saída, endereços internos devem ser permitidos em Permitir conexão interna não confiável.

A solicitação

O payload é enviado como JSON ou codificado em formulário, conforme o tipo de conteúdo do webhook:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "trigger": "message_action",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "post_root_id": "",
  "post_create_at": 1760009000000,
  "post_user_id": "…",
  "post_user_name": "jonas",
  "permalink": "https://chat.example.com/lumen-labs/pl/…",
  "text": "The staging database is full again",
  "files": [{"id": "…", "name": "df.txt", "link": "https://chat.example.com/api/v4/files/…"}],
  "priority": "",
  "requested_ack": false,
  "burn_on_read": false
}
  • user_id e user_name são da pessoa que selecionou a ação; post_user_id e post_user_name são do autor da mensagem.
  • Apenas aquela mensagem é enviada, nunca o restante do seu tópico.
  • files lista os arquivos da mensagem apenas quando a pessoa que selecionou a ação pode baixá-los. Baixar um link requer uma sessão ou um token, como qualquer arquivo da API.
  • Uma mensagem que se queima após a leitura é enviada sem seu texto e arquivos, com burn_on_read definido como true.
  • No formato codificado por formulário, os arquivos são enviados como campos repetidos de file_id, file_name e file_link, na mesma ordem.

A resposta

Responda como em qualquer webhook de saída (veja Responder a um webhook de saída): text ou attachments publica uma resposta no canal, e "response_type": "comment" publica-a no tópico da mensagem. Você também pode responder com ephemeral_text (limitado a 300 caracteres): ela é exibida apenas para a pessoa que selecionou a ação, na notificação. Um corpo vazio não publica nada.

{"ephemeral_text": "Ticket OPS-412 created"}

Com a API

  • GET /api/v4/channels/{channel_id}/message_actions: as ações que você pode selecionar em um canal, com id, display_name, description e icon_url. Nem tokens nem URLs de callback são retornados.
  • POST /api/v4/posts/{post_id}/message_actions/{hook_id}: executa uma ação em uma mensagem que você pode ler. Ela responde {"ephemeral_text"}.

Quando um webhook não funciona

  • 501 da URL do hook: os webhooks de entrada estão desativados no servidor.
  • 400 "Failed to decode the payload…": o JSON é inválido, ou o campo do formulário não se chama payload. "No text specified." significa que a requisição não tem nem text nem attachments.
  • 403: o webhook está vinculado a outro canal, ou seu proprietário não pode mais ler o canal.
  • Um webhook de saída nunca é acionado: o canal é privado, o gatilho não é a primeira palavra, a mensagem veio de um webhook, ou o webhook está configurado para acionar A partir do menu da mensagem.
  • Uma ação de mensagem não está no menu: o canal é privado, a ação está vinculada a outro canal, a pessoa é um convidado e a ação não tem canal, ou os webhooks de saída estão desativados.
  • 404 ao executar uma ação de mensagem: a ação não existe, ou ela não cobre o canal daquela mensagem para aquela pessoa. 429: a pessoa executou mais de 10 ações em um minuto. 502: nenhuma das URLs de callback pôde ser alcançada (o log contém o motivo).
  • Logs: com Ativar Debugging Webhook ativado (LogSettings.EnableWebhookDebugging) e o nível de log em DEBUG, o servidor registra os payloads de solicitações recebidas com falha. As chamadas de saída com falha são registradas como Outgoing Webhook POST failed.