Skip to main content
Webhooks permitem que a Liquera notifique o seu servidor automaticamente quando um pagamento é recebido, um saque é concluído ou qualquer outro evento relevante ocorre — sem que você precise fazer polling na API.

Como funcionam

Quando um evento ocorre, a Liquera envia uma requisição POST para a URL que você cadastrou, com um payload JSON descrevendo o evento. Se o seu servidor não retornar 2xx dentro do timeout (5 segundos), a Liquera fará até 3 tentativas com intervalo crescente antes de marcar a entrega como falha.

Estrutura do payload

Todo evento entregue pelo webhook segue o mesmo envelope:
{
  "event": "charge.paid",
  "timestamp": "2025-01-15T14:22:00.000Z",
  "data": {
    "chargeId": "clx3ghi789",
    "txid": "a1b2c3d4e5f67890abcdef1234567890",
    "amount": 9990,
    "paidAt": "2025-01-15T14:22:00.000Z",
    "payer": {
      "name": "João Silva",
      "document": "12345678901"
    }
  }
}
CampoTipoDescrição
eventstringNome do evento (ex: charge.paid)
timestampstringMomento do evento em ISO 8601
dataobjectPayload específico do evento (varia por tipo)

Verificação de assinatura (HMAC-SHA256)

Cada requisição de webhook inclui o header x-webhook-signature com uma assinatura HMAC-SHA256. Sempre valide esta assinatura para garantir que a requisição veio da Liquera e não foi adulterada.

Como calcular

A assinatura é calculada sobre o corpo bruto (raw body) da requisição:
HMAC-SHA256(secret, rawBody)

Exemplo em Node.js

import crypto from 'crypto';

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  // Comparação segura contra timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex')
  );
}

// No seu handler Express/Fastify:
app.post('/webhooks/liquera', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.LIQUERA_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).json({ message: 'Assinatura inválida' });
  }

  const event = JSON.parse(req.body);
  
  switch (event.event) {
    case 'charge.paid':
      // processar pagamento confirmado
      break;
    case 'withdraw.completed':
      // processar saque concluído
      break;
  }

  res.status(200).json({ received: true });
});
Sempre use o raw body (antes do JSON.parse) para calcular a assinatura. Usar req.body já parseado pode alterar a ordem dos campos e invalidar a verificação.

Eventos disponíveis

Cobranças

EventoQuando ocorre
charge.paidO pagamento PIX foi confirmado pelo banco
charge.refundedA cobrança foi estornada para o pagador
Payload do charge.paid:
{
  "chargeId": "clx3ghi789",
  "txid": "a1b2c3d4e5f67890abcdef1234567890",
  "amount": 9990,
  "paidAt": "2025-01-15T14:22:00.000Z",
  "payer": {
    "name": "João Silva",
    "document": "12345678901"
  }
}
Payload do charge.refunded:
{
  "refundId": "ref_abc123",
  "txid": "a1b2c3d4e5f67890abcdef1234567890",
  "chargeId": "clx3ghi789",
  "amount": "99.90",
  "status": "closed",
  "reason": "Solicitação do cliente",
  "end2endId": "E1234567820250115..."
}

Saques

EventoQuando ocorre
withdraw.completedA transferência PIX do saque foi concluída com sucesso
withdraw.failedO saque foi rejeitado pelo banco destino — saldo revertido automaticamente
withdraw.refundedA transferência foi devolvida pelo banco destino — saldo revertido automaticamente
Payload do withdraw.completed:
{
  "withdrawId": "clx5mno345",
  "amount": 50000,
  "status": "COMPLETED",
  "transferId": "tf_xyz789",
  "completedAt": "2025-01-15T15:05:00.000Z"
}
Payload do withdraw.failed:
{
  "withdrawId": "clx5mno345",
  "amount": 50000,
  "status": "FAILED",
  "reason": "Chave PIX inválida ou inexistente"
}

Chave PIX

EventoQuando ocorre
pixkey.updatedO status da sua chave PIX foi atualizado (ativação, inativação)
Payload:
{
  "keyId": "pix_key_id_acquirer",
  "key": "voce@empresa.com.br",
  "type": "EMAIL",
  "status": "ATIVA"
}

Infrações

EventoQuando ocorre
infraction.receivedNova infração PIX (MED) recebida
infraction.updatedStatus de uma infração foi atualizado
infraction.refund_completedReembolso de uma infração foi concluído

Wildcards

Se você criar um webhook sem especificar eventos, ele receberá todos os eventos automaticamente. Útil para logging geral ou durante desenvolvimento.

Logs de entrega

Você pode consultar os logs das últimas 20 entregas de cada webhook via GET /v1/webhooks/merchant. Cada log inclui:
  • O payload enviado
  • O status HTTP retornado pelo seu servidor
  • O número de tentativas realizadas
  • Se a entrega foi bem-sucedida
Use os logs para debugar problemas de integração sem precisar do suporte.

Boas práticas

  • Retorne 200 rapidamente: Processe o evento de forma assíncrona e retorne 200 OK imediatamente. Não faça operações lentas dentro do handler.
  • Seja idempotente: É possível receber o mesmo evento mais de uma vez (retries). Use o chargeId ou withdrawId para evitar processamento duplicado.
  • Valide sempre a assinatura: Nunca processe um evento sem verificar o x-webhook-signature.
  • Monitore os logs: Consulte periodicamente os logs de entrega para garantir que todos os eventos estão sendo processados com sucesso.