Antes dos webhooks existirem, integrar com qualquer API significava ficar fazendo polling: "já mudou? já mudou? já mudou?". Para pagamentos, isso era um pesadelo — você ou consultava de menos (descobria pagamento 10 minutos depois) ou de mais (gastava recursos e respeitava menos o rate limit da API).

Os webhooks resolveram isso de uma vez. São o jeito moderno de fazer comunicação entre sistemas em tempo real. Se você opera pagamentos online sem webhooks bem configurados, está pagando o preço em ineficiência operacional, atraso no atendimento ao cliente e perda de receita por automação travada.

O que é um webhook

Webhook é uma requisição HTTP que um sistema envia para uma URL sua quando algo acontece. Em vez de você perguntar "tem novidade?", o sistema avisa: "olha, aconteceu X agora".

Para pagamentos, os eventos típicos são:

  • charge.created — cobrança criada;
  • charge.paid — pagamento confirmado;
  • charge.failed — pagamento recusado;
  • charge.refunded — pagamento estornado;
  • charge.chargeback — chargeback recebido;
  • payout.processed — saque concluído;
  • payout.failed — saque falhou.

Cada evento dispara um POST para a URL que você configurou, com um payload JSON com todos os dados relevantes.

Como configurar

O fluxo, em qualquer gateway moderno (incluindo a ApexPy), é parecido:

  1. No painel administrativo, você cadastra uma URL de webhook (ex: https://sualoja.com.br/webhook/apexpy);
  2. Escolhe quais eventos quer receber (ou recebe todos);
  3. O gateway gera um segredo (secret) que você guarda em variável de ambiente;
  4. Configura sua URL pra responder POST e validar a assinatura HMAC.

Estrutura de um payload

Um webhook típico de pagamento confirmado:

POST /webhook/apexpy
Host: sualoja.com.br
Content-Type: application/json
X-Apexpy-Signature: sha256=a3f1e8b...
X-Apexpy-Event-Id: evt_91a8f2

{
  "event": "charge.paid",
  "created_at": "2026-05-22T14:32:09-03:00",
  "data": {
    "id": "ci_91a8f2",
    "amount": 24790,
    "currency": "BRL",
    "method": "pix",
    "status": "paid",
    "customer": {
      "name": "Maria Silva",
      "email": "[email protected]",
      "document": "12345678909"
    },
    "fees": 245,
    "net": 24545,
    "metadata": { "order_id": "12345" }
  }
}

Os 5 elementos importantes para você processar:

  • event: o tipo de evento (sempre você verifica antes de qualquer ação);
  • data.id: o ID único da cobrança (use isso pra atualizar seu pedido);
  • data.amount: valor em centavos (sempre confira contra o que você esperava);
  • data.status: estado atual da cobrança;
  • data.metadata: qualquer campo que VOCÊ enviou ao criar a cobrança (use para vincular ao seu sistema interno).

Verificação de assinatura HMAC: obrigatória

Sem validação de assinatura, qualquer pessoa que descubra sua URL pode disparar requests falsos tipo "pagamento confirmado". Você libera o produto, o "cliente" sai feliz, e nunca houve pagamento real.

A verificação é simples — basta calcular o HMAC-SHA256 do corpo da requisição com o seu segredo e comparar com o que veio no header X-Apexpy-Signature:

const crypto = require('crypto');
const SECRET = process.env.APEXPY_WEBHOOK_SECRET;

function verify(rawBody, signature) {
  const expected = crypto
    .createHmac('sha256', SECRET)
    .update(rawBody)
    .digest('hex');
  return `sha256=${expected}` === signature;
}
Cuidado com o body parser

Frameworks como Express por padrão fazem JSON.parse antes de você ver o body. Para validar HMAC corretamente, precisa do raw body. Use middleware específico (express.raw({ type: 'application/json' })) apenas na rota de webhook.

Idempotência: o evento pode chegar mais de uma vez

Gateways implementam retry automático em caso de falha. Se sua URL respondeu lento, ou retornou erro, ou estava offline, o webhook vai ser reenviado. Isso significa que o mesmo evento pode chegar 2, 3, 5 vezes — e você precisa estar preparado.

Implementação correta:

  1. Cada webhook traz um X-Apexpy-Event-Id (ID único do evento);
  2. Você guarda esse ID em uma tabela processed_webhooks;
  3. Antes de processar, checa: já existe esse ID? Se sim, retorna 200 sem fazer nada;
  4. Se não, processa e registra.
app.post('/webhook/apexpy', async (req, res) => {
  const eventId = req.headers['x-apexpy-event-id'];

  // Idempotência
  if (await db.processedWebhooks.exists(eventId)) {
    return res.status(200).send('already processed');
  }

  // Processa
  await processarEvento(req.body);
  await db.processedWebhooks.insert({ eventId, processedAt: new Date() });

  res.status(200).send('ok');
});

Retry exponencial: como funciona

Quando sua URL não responde 2xx, o gateway tenta de novo com intervalos crescentes. Na ApexPy o padrão é:

  • Tentativa 1: imediata;
  • Tentativa 2: após 30 segundos;
  • Tentativa 3: após 5 minutos;
  • Tentativa 4: após 30 minutos;
  • Tentativa 5: após 2 horas;
  • Tentativa 6 e além: a cada 4 horas até completar 24 horas.

Depois disso, o webhook é marcado como falhado permanentemente. Você precisa ter alertas para isso — significa que algo no seu sistema está quebrado há mais de um dia.

Responda rápido, processe depois

Webhooks têm timeout (5 a 30 segundos dependendo do gateway). Se seu processamento envolve coisas pesadas (enviar e-mail, gerar nota fiscal, sincronizar com ERP, processar imagem), não faça isso na rota do webhook.

O padrão correto:

  1. Webhook chega;
  2. Você valida assinatura;
  3. Você joga o evento em uma fila (Redis, RabbitMQ, SQS, BullMQ, Laravel Queues);
  4. Responde 200 OK imediatamente;
  5. Um worker assíncrono pega da fila e processa com calma.

Tempo médio de resposta do webhook deve ser menor que 200ms. Se for maior, repense a arquitetura.

Replay e inspeção

Gateways profissionais te dão duas ferramentas que valem ouro:

  • Log de webhooks enviados: você vê data, payload, resposta da sua URL, número de tentativas;
  • Replay manual: clica num botão e reenvia o evento — útil quando você corrigiu um bug e quer reprocessar.

Use isso constantemente em desenvolvimento e debug.

Webhooks em ambiente de desenvolvimento

Como receber webhook do gateway na sua máquina local? Use uma ferramenta de tunneling:

Você sobe seu servidor local na porta 3000, roda ngrok http 3000 e ganha uma URL pública tipo https://abc123.ngrok.io. Configura essa URL no painel do gateway e voilá — webhooks chegam direto no seu localhost.

Boas práticas resumidas

  1. Valide a assinatura HMAC sempre — sem exceção;
  2. Implemente idempotência usando o Event ID;
  3. Responda 200 em menos de 200ms — jogue o trabalho em fila;
  4. Use HTTPS na URL de webhook (HTTP simples vai falhar);
  5. Logue todos os webhooks recebidos (mesmo descartados por duplicidade);
  6. Monitore taxa de erro 5xx — alerta acima de 0,5%;
  7. Tenha uma rota separada por gateway (não misture);
  8. Documente internamente o que cada evento dispara no seu sistema;
  9. Configure timeout no seu reverse proxy compatível com o gateway;
  10. Teste em sandbox simulando todos os eventos possíveis antes de subir pra produção.

Webhooks ApexPy com HMAC, retry e replay

Toda a infraestrutura pronta — você só implementa o endpoint. Painel de inspeção e replay incluso.

Ver documentação

Conclusão

Webhooks não são complicados — são obrigatórios. Sem eles, sua operação fica reativa, com clientes esperando confirmação de pagamento que você só vê meia hora depois quando lembra de checar.

Implementação mínima cabe em 30 linhas de código + tabela de idempotência. Implementação ouro inclui fila assíncrona, alertas, dashboard de monitoramento.

Comece simples, evolua com a operação. Mas comece — porque qualquer minuto de atraso na confirmação de um pagamento é dinheiro deixado na mesa.

Última atualização: 17 de maio de 2026