Depuração6 de agosto de 20268 min de leitura

Webhooks do WooCommerce não são enviados na hora do pedido

O WooCommerce enfileira webhooks no Action Scheduler via WP-Cron, que roda quando alguém visita o site. Mais de cinco falhas seguidas desativam o webhook.

O PEDIDO É FEITO, O WEBHOOK NÃO É ENVIADOpedido feitoAction Schedulerwoocommerce_deliver_webhook_asyncesperapor uma visitaenviadoo WP-Cron não é um relógio. ele roda quando alguém visita o site.numa loja tranquila, são minutos. numa muito tranquila, são horas.mais de cinco falhas consecutivas e o WooCommerce desativa o webhook de vez
O pedido é feito na hora. A entrega espera a próxima visualização de página, porque o WP-Cron não é um relógio.

Todos os outros artigos sobre webhooks, incluindo o resto dos nossos, partem da mesma premissa: o provedor enviou o evento na hora e algo deu errado depois. O WooCommerce quebra essa premissa antes mesmo de a requisição sair do servidor.

O evento não é enviado quando o pedido é feito. Ele vai para uma fila, a fila é esvaziada pelo cron do WordPress, e o cron do WordPress não é um cron. Ele roda quando alguém carrega uma página.

Se sua loja é movimentada, o atraso é de até cerca de um minuto e você nunca vai perceber. Se sua loja recebe poucos visitantes por hora, a notificação de pedido "em tempo real" chega quando o próximo visitante resolver aparecer.

TL;DR

  • As entregas entram na fila como ações woocommerce_deliver_webhook_async no Action Scheduler
  • O Action Scheduler é movido pelo WP-Cron, que dispara a cada carregamento de página, e não em horários definidos
  • Por isso, uma loja com pouco tráfego tem entrega de webhooks lenta e imprevisível, e nada disso é defeito
  • "O WooCommerce desativa automaticamente um webhook depois de mais de cinco falhas de entrega consecutivas"
  • Uma falha é qualquer resposta que não seja 2xx, 301 ou 302
  • A solução de verdade em WordPress self-hosted é desativar o WP-Cron e acioná-lo por um cron do sistema

Comece verificando se o webhook foi enviado

Antes de depurar seu endpoint, descubra qual destes dois problemas bem diferentes você tem: a entrega falhou, ou a entrega ainda não aconteceu.

WooCommerce → Settings → Advanced → Webhooks (Configurações → Avançado → Webhooks) mostra o status de cada webhook, e WooCommerce → Status → Logs (origem webhooks-delivery) mostra as entregas recentes com o código de resposta. Se as entregas aparecem e estão falhando, pule para o resto do checklist, mais abaixo. Se o log está vazio e o pedido claramente existe, a entrega ainda está parada na fila.

O PEDIDO É FEITO, O WEBHOOK NÃO É ENVIADOpedido feitoAction Schedulerwoocommerce_deliver_webhook_asyncesperapor uma visitaenviadoo WP-Cron não é um relógio. ele roda quando alguém visita o site.numa loja tranquila, são minutos. numa muito tranquila, são horas.mais de cinco falhas consecutivas e o WooCommerce desativa o webhook de vez

Para ver a própria fila, abra a tela do Action Scheduler no admin, em Tools → Scheduled Actions (Ferramentas → Ações agendadas), e filtre por woocommerce_deliver_webhook_async. Ações pendentes com timestamps no passado são a prova cabal: já deviam ter rodado, e nada as executou.

Por que o WP-Cron se comporta assim

O WordPress não tem processo em segundo plano. O que ele chama de cron é uma lista de tarefas pendentes verificada a cada requisição recebida, então o relógio só anda quando chega tráfego. É um design razoável para hospedagem compartilhada em 2005 e ruim para qualquer coisa sensível a tempo.

As consequências para webhooks, especificamente:

A latência de entrega acompanha seu tráfego, não o evento. Uma loja com tráfego constante entrega em até cerca de um minuto. Uma loja B2B em que os pedidos chegam de madrugada e ninguém navega até de manhã pode ficar horas com uma entrega parada na fila.

O acúmulo se agrava. Ações com falha ficam na tabela, e, em lojas que rodam há um tempo, as tabelas do Action Scheduler crescem a ponto de deixar lentas justamente as requisições que deveriam esvaziá-las.

Trabalho disparado por carregamento de página não é confiável com cache. Um cache de página inteira ou uma CDN na frente do WordPress faz com que muitas visitas nunca cheguem ao PHP, e, portanto, nunca façam o cron andar.

A solução é operação padrão de WordPress e vale a pena em qualquer loja em que o webhook importa:

// wp-config.php
define('DISABLE_WP_CRON', true);
# then drive it from a real scheduler, every minute
* * * * * cd /var/www/store && wp cron event run --due-now >/dev/null 2>&1

wp action-scheduler run é o equivalente para esvaziar a fila do Action Scheduler diretamente, se você tiver o pacote do WP-CLI disponível. Quando o cron roda num timer de verdade, a latência de entrega deixa de depender de alguém estar navegando.

Mais de cinco falhas e o webhook some

É esta parte que transforma um problema temporário num problema permanente.

"O WooCommerce desativa automaticamente um webhook depois de mais de cinco falhas de entrega consecutivas." A definição de falha é ampla: "qualquer resposta que não tenha um código de status HTTP 2xx, 301 ou 302. Por exemplo, respostas 4xx ou 5xx contam como falhas."

É um número pequeno. Um deploy que derruba seu endpoint por dois minutos, numa loja com fluxo constante de pedidos, consome essa quantidade de entregas sem dificuldade. Quando isso acontece, o status do webhook muda para desativado e fica assim. Nenhum e-mail, nenhum aviso no admin, nada que apareça diante de um humano. Os pedidos continuam sendo criados e nada é enviado, o que parece exatamente um dia de vendas fraco.

Nada disso é exclusivo do WooCommerce. Webhook do n8n não funciona ordena as sete causas do lado da automação pela frequência com que cada uma acaba sendo a culpada, e, quando uma fila se esvazia de forma tão irregular quanto esta, a entrega fora de ordem vira rotina, que é o assunto de O HubSpot avisa que o eventId dele pode não ser único. Quando as novas tentativas de fato chegam em dobro, Reserva duplicada mostra como isso aparece para a pessoa dona do pedido.

É o mesmo formato de falha da Shopify excluindo a inscrição, com duas diferenças que o tornam pior: o limite é de mais de cinco falhas consecutivas, e não de oito, como na Shopify, e não há nenhum e-mail de aviso.

Se você roda WooCommerce em produção, monitore o status do webhook. Uma tarefa agendada que lê o webhook pela API REST e alerta se status !== 'active' quase não custa nada e é a única coisa que vai avisar você.

Verificação de assinatura

O WooCommerce envia o cabeçalho X-WC-Webhook-Signature, um HMAC-SHA256 em base64 do corpo bruto da requisição, calculado com o segredo que você configurou no webhook.

Base64, e não hex: a mesma convenção da Shopify e o oposto da Stripe e do GitHub. A codificação que cada provedor escolheu está na referência de provedores de webhook. Se você usa uma função de verificação compartilhada entre provedores, essa diferença de codificação é uma fonte comum de "a assinatura nunca bate" com um payload que parece perfeito.

import crypto from "node:crypto";

function verifyWooCommerce(raw: string, header: string | null, secret: string) {
  if (!header) return false;
  const expected = crypto.createHmac("sha256", secret).update(raw, "utf8").digest("base64");
  const a = Buffer.from(expected);
  const b = Buffer.from(header);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Como em todo lugar, calcule o hash dos bytes que você recebeu, e não de um objeto serializado de novo. A comparação entre provedores está em Como verificar assinaturas de webhook da Stripe, do GitHub e da Shopify.

Uma pegadinha específica do WooCommerce: se o webhook foi criado sem segredo, a assinatura é gerada a partir do material de chave do próprio site, e não de algo que você escolheu, e sua verificação vai falhar por motivos que não têm nada a ver com seu código. Defina um segredo explicitamente.

O resto do checklist

Siga estes itens quando as entregas existem e estão falhando.

O status é active, e não paused ou disabled. Confira isso primeiro, porque o estado desativado explica todo o resto de uma vez.

O tópico corresponde ao evento que você imagina. order.created dispara na criação, que, em muitos gateways de pagamento, acontece enquanto o pedido ainda está pending. Se você está esperando o pagamento, order.updated com uma checagem de status costuma ser o que você quer. Muitos relatos de "webhook não dispara" são, na verdade, "dispara num evento diferente do esperado".

A URL de entrega é acessível a partir do servidor, e não só do seu notebook. Lojas atrás de uma rede corporativa ou em hosts com regras restritivas de saída podem falhar aqui em silêncio.

Um plugin está interrompendo a ação. Os hooks do WooCommerce aceitam filtros, e plugins de cache, segurança ou desempenho já foram vistos interferindo no Action Scheduler. Testar com os plugins desativados não tem glamour e muitas vezes resolve.

A versão da API do webhook. Os webhooks do WooCommerce têm payloads versionados, e um webhook v1 criado anos atrás envia um formato diferente do v3. Se seu handler começou a falhar depois de uma atualização do WooCommerce, confira em qual versão o webhook está fixado.

Onde o AnyHook entra

Dois dos problemas acima são estruturais, e nenhum dos dois se resolve com um handler melhor.

O primeiro é a desativação por falhas consecutivas. Aponte o webhook para in.anyhook.net/you/woo e o AnyHook responde 200 em cerca de um segundo a partir da edge, então o contador de falhas consecutivas deixa de depender do que seu próprio endpoint está fazendo. As novas tentativas contra seu endpoint seguem o cronograma do AnyHook, não o do WooCommerce, e o webhook continua ativo.

O segundo é que o log de entregas do próprio WooCommerce fica dentro da loja, com a retenção da loja, numa tela do admin. O AnyHook guarda cada evento com cabeçalhos e corpo completos, com criptografia em repouso e replay (um novo envio de um evento armazenado, feito por você) por intervalo de tempo, então a janela de um deploy pode ser recuperada sem tocar no WordPress.

  • Alertas de falha com 1, 5 e 20 falhas consecutivas, que é a notificação que o WooCommerce não envia
  • Novas tentativas de entrega com backoff exponencial, por muito mais tempo que uma única tentativa
  • Um único cabeçalho AnyHook-Signature em vez da variante em base64, se você recebe de várias plataformas

O que um relay de webhooks (um serviço que recebe, guarda e encaminha seus webhooks) não resolve é a fila que fica antes dele. Se o WP-Cron não está rodando, o evento nunca chega a lugar nenhum. Corrija o cron primeiro; o relay cuida de tudo depois disso.

Conclusão

O WooCommerce é a única grande plataforma em que "o webhook está atrasado" normalmente não é bug nem culpa do seu endpoint. Confira a fila do Action Scheduler antes de qualquer outra coisa e, se o tráfego da loja é baixo, passe o cron para um agendador de verdade.

Depois defina um segredo, verifique sobre os bytes brutos com base64 e monitore o status do próprio webhook. Um punhado de falhas consecutivas não dá muita margem, e a desativação chega sem aviso nenhum.

Todos os posts6 de agosto de 2026 · 8 min

Pare de perder webhooks.

Troque uma URL. Tenha novas tentativas, um log de eventos e replay com um clique. Ou veja antes: crie uma conta, rode a simulação de queda de 30 segundos e veja um evento sobreviver ao seu servidor fora do ar. Não precisa de servidor.