{"id":8,"date":"2026-08-19T13:32:51","date_gmt":"2026-08-19T13:32:51","guid":{"rendered":"https:\/\/postping.com.br\/blog\/o-que-e-webhook\/"},"modified":"2026-08-19T13:32:51","modified_gmt":"2026-08-19T13:32:51","slug":"o-que-e-webhook","status":"publish","type":"post","link":"https:\/\/postping.com.br\/blog\/o-que-e-webhook\/","title":{"rendered":"O que \u00e9 um webhook e como avisar seu time a cada post"},"content":{"rendered":"<p>Webhook \u00e9 um endere\u00e7o de URL que outro servi\u00e7o entrega para voc\u00ea, e que serve para avisar quando alguma coisa acontece do seu lado. Seu site faz um <code>POST<\/code> nesse endere\u00e7o levando um JSON curto que descreve o evento, e quem est\u00e1 do outro lado decide o que fazer com aquilo: virar mensagem num canal, linha num banco, gatilho de uma automa\u00e7\u00e3o.<\/p>\n<p>Para quem mant\u00e9m um blog, o evento quase sempre \u00e9 o mesmo: saiu artigo novo. E o destino costuma ser o lugar onde a equipe j\u00e1 passa o dia, que para muita gente \u00e9 um canal do Discord ou um grupo do Telegram.<\/p>\n<h2>Quem chama quem<\/h2>\n<p>Uma API comum funciona no sentido de dentro para fora: seu c\u00f3digo pergunta, o servi\u00e7o responde. Se voc\u00ea quer saber se saiu artigo novo, pergunta de novo daqui a cinco minutos. \u00c9 a diferen\u00e7a entre ligar para a gr\u00e1fica de hora em hora para saber se o material ficou pronto e deixar o telefone para eles ligarem quando ficar.<\/p>\n<p>O webhook inverte a dire\u00e7\u00e3o. Ningu\u00e9m pergunta nada: quando o evento acontece, quem tem a informa\u00e7\u00e3o sai avisando. Isso muda duas coisas na pr\u00e1tica. 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\u00e7o que quase sempre responde que n\u00e3o houve novidade.<\/p>\n<p>A palavra aparece nos dois sentidos, e \u00e9 a\u00ed que a confus\u00e3o come\u00e7a. Quando voc\u00ea configura um webhook no Discord, voc\u00ea \u00e9 quem envia. Quando um servi\u00e7o de pagamento pede a sua URL de webhook, voc\u00ea \u00e9 quem recebe. Mesma ideia, lados opostos do fio, e o esfor\u00e7o de implementa\u00e7\u00e3o \u00e9 completamente diferente: enviar \u00e9 uma requisi\u00e7\u00e3o HTTP; receber exige um endere\u00e7o p\u00fablico, valida\u00e7\u00e3o de assinatura e uma resposta r\u00e1pida.<\/p>\n<h2>O que vai dentro da requisi\u00e7\u00e3o<\/h2>\n<p>O caso do Discord \u00e9 o mais direto de olhar porque a documenta\u00e7\u00e3o \u00e9 curta. O endere\u00e7o que o painel entrega tem a forma <code>\/webhooks\/{webhook.id}\/{webhook.token}<\/code>, e o token est\u00e1 ali na pr\u00f3pria URL. Quem tem o link publica no canal, ent\u00e3o essa URL \u00e9 credencial: n\u00e3o vai para o reposit\u00f3rio nem para print de tutorial.<\/p>\n<p>Voc\u00ea manda um <code>POST<\/code> com um corpo JSON. O campo <code>content<\/code> aceita at\u00e9 2000 caracteres e \u00e9 o texto solto da mensagem. O campo <code>embeds<\/code> aceita at\u00e9 10 objetos, e \u00e9 o que produz aquele bloco com barra colorida na lateral, t\u00edtulo clic\u00e1vel, descri\u00e7\u00e3o e imagem. D\u00e1 para trocar o nome e o avatar de quem assina a mensagem com <code>username<\/code> e <code>avatar_url<\/code>. A documenta\u00e7\u00e3o exige que pelo menos um entre <code>content<\/code>, <code>embeds<\/code>, <code>components<\/code>, <code>file<\/code> ou <code>poll<\/code> venha preenchido; corpo vazio n\u00e3o passa.<\/p>\n<p>Para aviso de artigo novo, o embed \u00e9 o formato que rende. T\u00edtulo do post no campo de t\u00edtulo, o link no campo de URL, a imagem destacada como imagem do embed e a cor da categoria na barra lateral. Quem l\u00ea o canal decide se abre sem precisar clicar para descobrir do que se trata.<\/p>\n<h2>Onde o WordPress dispara isso<\/h2>\n<p>O WordPress j\u00e1 tem o gancho pronto. A a\u00e7\u00e3o <code>transition_post_status<\/code> recebe tr\u00eas argumentos, <code>$new_status<\/code>, <code>$old_status<\/code> e o objeto <code>$post<\/code>, e \u00e9 onde se pendura o envio.<\/p>\n<p>Tem uma armadilha documentada nela, e \u00e9 a origem cl\u00e1ssica do canal que amanhece com mensagem repetida: apesar do nome, o gancho n\u00e3o dispara s\u00f3 quando o status muda. Ele tamb\u00e9m dispara quando o post \u00e9 atualizado com o status intacto. Sem a verifica\u00e7\u00e3o de que <code>$old_status<\/code> era diferente de <code>publish<\/code>, cada corre\u00e7\u00e3o de v\u00edrgula num artigo antigo vira um aviso novo no canal. A documenta\u00e7\u00e3o sugere a sa\u00edda em uma linha, comparando os dois status e abandonando cedo quando forem iguais.<\/p>\n<p>O envio em si \u00e9 <code>wp_remote_post( $url, $args )<\/code>, que devolve um array com a resposta ou um <code>WP_Error<\/code>. Em <code>$args<\/code> v\u00e3o o <code>body<\/code> com o JSON, os <code>headers<\/code> e o <code>timeout<\/code>. Um detalhe de seguran\u00e7a que a pr\u00f3pria refer\u00eancia marca: quando a URL vier de um campo preenchido pelo usu\u00e1rio, e a URL de webhook sempre vem, o correto \u00e9 <code>wp_safe_remote_post()<\/code>, que barra requisi\u00e7\u00f5es para endere\u00e7os internos.<\/p>\n<p>Escrito \u00e0 m\u00e3o, esse c\u00f3digo costuma acabar no <code>functions.php<\/code> do tema, e vai embora junto com o tema na pr\u00f3xima troca de layout. Quem n\u00e3o quer manter isso escolhe um plugin: o <a href=\"https:\/\/postping.com.br\/recursos\">Post Ping<\/a> 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.<\/p>\n<h2>Telegram \u00e9 chamada de API, n\u00e3o webhook<\/h2>\n<p>Aqui vale desfazer um mal-entendido que custa tempo. Para mandar mensagem num grupo do Telegram, voc\u00ea n\u00e3o usa webhook: voc\u00ea chama a Bot API. O endere\u00e7o \u00e9 <code>https:\/\/api.telegram.org\/bot&lt;token&gt;\/METHOD_NAME<\/code>, e o m\u00e9todo \u00e9 <code>sendMessage<\/code>, com dois par\u00e2metros obrigat\u00f3rios, <code>chat_id<\/code> e <code>text<\/code>. O texto aceita de 1 a 4096 caracteres, bem mais folga que os 2000 do Discord.<\/p>\n<p>O <code>chat_id<\/code> aceita n\u00famero ou string, e a string pode ser o nome de usu\u00e1rio do grupo ou canal no formato <code>@username<\/code>. A resposta vem em JSON com um campo <code>ok<\/code>: quando d\u00e1 certo, <code>ok<\/code> \u00e9 verdadeiro e o conte\u00fado est\u00e1 em <code>result<\/code>; quando falha, <code>ok<\/code> vem falso acompanhado de <code>error_code<\/code> e de uma <code>description<\/code> em texto, que costuma dizer com todas as letras o que faltou.<\/p>\n<p>Webhook existe no Telegram, mas na dire\u00e7\u00e3o contr\u00e1ria. \u00c9 o que voc\u00ea configura para receber as mensagens que as pessoas mandam para o seu bot, em vez de ficar consultando o servidor atr\u00e1s de atualiza\u00e7\u00f5es. Quem s\u00f3 quer avisar o grupo a cada publica\u00e7\u00e3o n\u00e3o precisa dele em momento nenhum.<\/p>\n<h2>Como saber que a mensagem chegou<\/h2>\n<p>Por padr\u00e3o, o Discord responde <code>204 No Content<\/code> ao executar um webhook. Corpo vazio, nenhuma confirma\u00e7\u00e3o de que a mensagem foi mesmo salva. A documenta\u00e7\u00e3o avisa em voz alta: sem a query <code>wait=true<\/code>, mensagens que n\u00e3o foram gravadas n\u00e3o retornam erro. Com <code>wait=true<\/code>, a API espera a confirma\u00e7\u00e3o do servidor e devolve o corpo da mensagem criada. \u00c9 uma requisi\u00e7\u00e3o um pouco mais lenta e a \u00fanica forma de o seu c\u00f3digo saber o que aconteceu.<\/p>\n<p>Depois vem o sil\u00eancio, que \u00e9 pior que o erro. Canal apagado, webhook removido por outra pessoa da equipe, bot expulso do grupo: nada disso levanta a m\u00e3o. O canal simplesmente para de receber aviso, e ningu\u00e9m estranha, porque aus\u00eancia de mensagem parece dia sem publica\u00e7\u00e3o. \u00c9 por isso que o Post Ping roda uma verifica\u00e7\u00e3o di\u00e1ria de artigos publicados que n\u00e3o foram notificados, comparando o que saiu no blog com o que foi realmente enviado.<\/p>\n<p>Antes de confiar em qualquer envio autom\u00e1tico, feche o ciclo na m\u00e3o uma vez. Dispare um <code>POST<\/code> de teste para a URL do webhook com um <code>content<\/code> 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\u00e7\u00e3o de status no gancho. Feitos os tr\u00eas, o canal pode ser tratado como fonte confi\u00e1vel do que foi ao ar. A <a href=\"https:\/\/postping.com.br\/documentacao\">documenta\u00e7\u00e3o do plugin<\/a> tem o passo de conex\u00e3o para quem preferir n\u00e3o escrever c\u00f3digo.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>O que \u00e9 webhook explicado para quem edita um blog: como um POST em JSON avisa o Discord e o Telegram a cada artigo publicado, e por que o aviso falha calado.<\/p>\n","protected":false},"author":1,"featured_media":7,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-8","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-webhooks"],"_links":{"self":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts\/8","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/comments?post=8"}],"version-history":[{"count":0,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts\/8\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/media\/7"}],"wp:attachment":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/media?parent=8"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/categories?post=8"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/tags?post=8"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}