O que é um webhook e como avisar seu time a cada post

Ilustração abstrata com nós luminosos e linhas de conexão partindo de um ponto central, em degradê violeta, índigo e ciano sobre fundo azul-marinho escuro.

Webhook é um endereço de URL que outro serviço entrega para você, e que serve para avisar quando alguma coisa acontece do seu lado. Seu site faz um POST nesse endereço levando um JSON curto que descreve o evento, e quem está do outro lado decide o que fazer com aquilo: virar mensagem num canal, linha num banco, gatilho de uma automação.

Para quem mantém um blog, o evento quase sempre é o mesmo: saiu artigo novo. E o destino costuma ser o lugar onde a equipe já passa o dia, que para muita gente é um canal do Discord ou um grupo do Telegram.

Quem chama quem

Uma API comum funciona no sentido de dentro para fora: seu código pergunta, o serviço responde. Se você quer saber se saiu artigo novo, pergunta de novo daqui a cinco minutos. É a diferença entre ligar para a gráfica de hora em hora para saber se o material ficou pronto e deixar o telefone para eles ligarem quando ficar.

O webhook inverte a direção. Ninguém pergunta nada: quando o evento acontece, quem tem a informação sai avisando. Isso muda duas coisas na prática. A mensagem chega no segundo em que o artigo entra no ar, sem janela de espera. E some o trabalho de consultar de minuto em minuto um endereço que quase sempre responde que não houve novidade.

A palavra aparece nos dois sentidos, e é aí que a confusão começa. Quando você configura um webhook no Discord, você é quem envia. Quando um serviço de pagamento pede a sua URL de webhook, você é quem recebe. Mesma ideia, lados opostos do fio, e o esforço de implementação é completamente diferente: enviar é uma requisição HTTP; receber exige um endereço público, validação de assinatura e uma resposta rápida.

O que vai dentro da requisição

O caso do Discord é o mais direto de olhar porque a documentação é curta. O endereço que o painel entrega tem a forma /webhooks/{webhook.id}/{webhook.token}, e o token está ali na própria URL. Quem tem o link publica no canal, então essa URL é credencial: não vai para o repositório nem para print de tutorial.

Você manda um POST com um corpo JSON. O campo content aceita até 2000 caracteres e é o texto solto da mensagem. O campo embeds aceita até 10 objetos, e é o que produz aquele bloco com barra colorida na lateral, título clicável, descrição e imagem. Dá para trocar o nome e o avatar de quem assina a mensagem com username e avatar_url. A documentação exige que pelo menos um entre content, embeds, components, file ou poll venha preenchido; corpo vazio não passa.

Para aviso de artigo novo, o embed é o formato que rende. Título do post no campo de título, o link no campo de URL, a imagem destacada como imagem do embed e a cor da categoria na barra lateral. Quem lê o canal decide se abre sem precisar clicar para descobrir do que se trata.

Onde o WordPress dispara isso

O WordPress já tem o gancho pronto. A ação transition_post_status recebe três argumentos, $new_status, $old_status e o objeto $post, e é onde se pendura o envio.

Tem uma armadilha documentada nela, e é a origem clássica do canal que amanhece com mensagem repetida: apesar do nome, o gancho não dispara só quando o status muda. Ele também dispara quando o post é atualizado com o status intacto. Sem a verificação de que $old_status era diferente de publish, cada correção de vírgula num artigo antigo vira um aviso novo no canal. A documentação sugere a saída em uma linha, comparando os dois status e abandonando cedo quando forem iguais.

O envio em si é wp_remote_post( $url, $args ), que devolve um array com a resposta ou um WP_Error. Em $args vão o body com o JSON, os headers e o timeout. Um detalhe de segurança que a própria referência marca: quando a URL vier de um campo preenchido pelo usuário, e a URL de webhook sempre vem, o correto é wp_safe_remote_post(), que barra requisições para endereços internos.

Escrito à mão, esse código costuma acabar no functions.php do tema, e vai embora junto com o tema na próxima troca de layout. Quem não quer manter isso escolhe um plugin: o Post Ping dispara o embed no Discord com imagem, cor e link a cada artigo publicado, e a mensagem no Telegram pela Bot API, incluindo canal separado por idioma quando o site roda com Polylang.

Telegram é chamada de API, não webhook

Aqui vale desfazer um mal-entendido que custa tempo. Para mandar mensagem num grupo do Telegram, você não usa webhook: você chama a Bot API. O endereço é https://api.telegram.org/bot<token>/METHOD_NAME, e o método é sendMessage, com dois parâmetros obrigatórios, chat_id e text. O texto aceita de 1 a 4096 caracteres, bem mais folga que os 2000 do Discord.

O chat_id aceita número ou string, e a string pode ser o nome de usuário do grupo ou canal no formato @username. A resposta vem em JSON com um campo ok: quando dá certo, ok é verdadeiro e o conteúdo está em result; quando falha, ok vem falso acompanhado de error_code e de uma description em texto, que costuma dizer com todas as letras o que faltou.

Webhook existe no Telegram, mas na direção contrária. É o que você configura para receber as mensagens que as pessoas mandam para o seu bot, em vez de ficar consultando o servidor atrás de atualizações. Quem só quer avisar o grupo a cada publicação não precisa dele em momento nenhum.

Como saber que a mensagem chegou

Por padrão, o Discord responde 204 No Content ao executar um webhook. Corpo vazio, nenhuma confirmação de que a mensagem foi mesmo salva. A documentação avisa em voz alta: sem a query wait=true, mensagens que não foram gravadas não retornam erro. Com wait=true, a API espera a confirmação do servidor e devolve o corpo da mensagem criada. É uma requisição um pouco mais lenta e a única forma de o seu código saber o que aconteceu.

Depois vem o silêncio, que é pior que o erro. Canal apagado, webhook removido por outra pessoa da equipe, bot expulso do grupo: nada disso levanta a mão. O canal simplesmente para de receber aviso, e ninguém estranha, porque ausência de mensagem parece dia sem publicação. É por isso que o Post Ping roda uma verificação diária de artigos publicados que não foram notificados, comparando o que saiu no blog com o que foi realmente enviado.

Antes de confiar em qualquer envio automático, feche o ciclo na mão uma vez. Dispare um POST de teste para a URL do webhook com um content qualquer e confirme que o status voltou como esperado. Publique um rascunho de verdade e cronometre quantos segundos a mensagem leva para aparecer no canal. Edite esse mesmo artigo e verifique que nenhum aviso novo saiu; se saiu, falta a comparação de status no gancho. Feitos os três, o canal pode ser tratado como fonte confiável do que foi ao ar. A documentação do plugin tem o passo de conexão para quem preferir não escrever código.

Este blog publica sozinho nas redes

Cada artigo daqui vira post no Instagram e no Facebook automaticamente: legenda escrita por IA, card visual gerado na hora. Quem faz isso é o Post Ping, o mesmo plugin que você pode instalar no seu WordPress.

Ver planos do Post Ping