PIX IN

Os webhooks são notificações HTTP automáticas enviadas pela API de Pagamentos sempre que há mudanças importantes no status de um pagamento PIX IN (recebimento). Eles permitem que seu sistema seja notificado em tempo real sobre eventos relacionados aos pagamentos, eliminando a necessidade de polling constante da API.


Configuração

A URL de webhook é configurada no cadastro da sua conta. Todas as notificações de eventos PIX IN serão enviadas automaticamente para essa URL.

📘

Dica

Caso precise de múltiplas URLs de webhook (até 10), entre em contato com nosso suporte para configurar URLs adicionais com filtro por tipo de evento.

Requisitos do Endpoint

Seu endpoint de webhook deve:

  • Aceitar requisições POST
  • Responder com status HTTP 200 para confirmar recebimento
  • Processar o payload JSON enviado no body
  • Responder em até 10 segundos (timeout da nossa API)
  • Usar HTTPS (recomendado para segurança)
  • Implementar idempotência usando o header Idempotency-Key

Eventos Disponíveis

📋 Lista de Eventos

EventoDescrição
pix-in.waiting_paymentUm novo QR Code PIX foi gerado e está aguardando o pagamento pelo cliente.
pix-in.paidO pagamento PIX foi recebido e confirmado com sucesso. O saldo da conta foi creditado.
pix-in.refusedO pagamento foi recusado pelo banco ou processador.
pix-in.canceledO pagamento foi cancelado antes de ser concluído.
pix-in.refundedO pagamento foi reembolsado. O valor líquido foi debitado do saldo da conta.
pix-in.failedOcorreu uma falha no processamento do pagamento.
pix-in.expiredO QR Code expirou sem que o pagamento fosse realizado.
pix-in.in_analysisO pagamento está em análise pelo processador.
pix-in.chargedbackO pagamento sofreu chargeback. O valor líquido foi debitado do saldo da conta.
pix-in.in_protestO pagamento está em protesto.

🔄 Fluxo Típico de Eventos

O fluxo mais comum para um pagamento PIX IN bem-sucedido é:

waiting_payment → paid

Fluxos alternativos:

waiting_payment → expired          (QR Code expirou)
waiting_payment → canceled         (pagamento cancelado)
waiting_payment → refused          (pagamento recusado)
waiting_payment → failed           (falha no processamento)
paid → refunded                    (reembolso após pagamento)
paid → chargedback                 (chargeback após pagamento)

Status de Pagamentos PIX IN

🚦 Todos os Status Possíveis

StatusDescriçãoFinal?Impacto no Saldo
waiting_paymentQR Code gerado, aguardando pagamentoNãoNenhum
paidPagamento confirmadoNão+Crédito (valor líquido)
in_analysisPagamento em análiseNãoNenhum
refusedPagamento recusadoSimNenhum
canceledPagamento canceladoSimNenhum
expiredQR Code expiradoSimNenhum
failedFalha no processamentoSimNenhum
refundedPagamento reembolsadoSim-Débito (valor líquido)
chargedbackChargeback recebidoSim-Débito (valor líquido)
in_protestPagamento em protestoNãoNenhum
🚧

Importante

Status marcados como Final indicam que a transação não sofrerá mais mudanças. Exceto paid, que pode transicionar para refunded ou chargedback.

🔀 Transições de Status

                         ┌──────────────┐
                         │   expired    │ (final)
                         └──────────────┘
                               ▲
                               │
┌──────────────────┐     ┌─────┴────┐     ┌──────────────┐
│                  │     │          │     │   refused    │ (final)
│  (QR Code gerado)├────►│ waiting  ├────►└──────────────┘
│                  │     │ payment  │
└──────────────────┘     │          ├────►┌──────────────┐
                         └────┬─────┘     │   canceled   │ (final)
                              │           └──────────────┘
                              │
                              │           ┌──────────────┐
                              │           │    failed    │ (final)
                              ├──────────►└──────────────┘
                              │
                              ▼
                         ┌──────────┐     ┌──────────────┐
                         │          ├────►│   refunded   │ (final)
                         │   paid   │     └──────────────┘
                         │          ├────►┌──────────────┐
                         └──────────┘     │ chargedback  │ (final)
                                          └──────────────┘

Formato do Payload

Estrutura Base

Todos os eventos seguem a mesma estrutura base. O campo data contém os dados da transação no momento do evento.

{
  "id": "evt_a1b2c3d4e5f6a1b2c3d4e5f6",
  "event": "pix-in.{status}",
  "type": "pix-in",
  "created_at": "2026-02-15T14:30:00.123Z",
  "data": {
    // Dados da transação (veja abaixo)
  }
}
CampoTipoDescrição
idStringIdentificador único do evento. Prefixo evt_. Use para idempotência.
eventStringNome do evento no formato pix-in.{status}.
typeStringTipo do recurso. Sempre "pix-in" para pagamentos PIX.
created_atStringTimestamp ISO 8601 de quando o evento foi criado.
dataObjectDados da transação no momento do evento (detalhado abaixo).

Objeto data (Transação PIX IN)

CampoTipoDescrição
data.idString (UUID)ID único da transação no nosso sistema.
data.statusStringStatus atual da transação (ex: paid, expired).
data.amountIntegerValor bruto do pagamento em centavos (ex: 10000 = R$ 100,00).
data.currencyStringCódigo da moeda. Sempre "BRL".
data.feeObject | nullTaxas aplicadas. Contém total_fee e net_amount (em centavos).
data.fee.total_feeIntegerTaxa total cobrada em centavos.
data.fee.net_amountIntegerValor líquido creditado em centavos (amount - total_fee).
data.paid_atString | nullTimestamp ISO 8601 do momento do pagamento. null se ainda não pago.
data.created_atStringTimestamp ISO 8601 da criação da transação.
data.customerObject | nullDados do pagador (quando disponível).
data.customer.nameString | nullNome do pagador.
data.customer.documentObject | nullDocumento do pagador (type e number).
data.customer.emailString | nullEmail do pagador.
data.customer.phoneString | nullTelefone do pagador.
data.pixObjectDados do PIX.
data.pix.end_to_end_idString | nullIdentificador end-to-end do PIX no Banco Central. Disponível após confirmação.
data.pix.qrcodeString | nullCódigo copia-e-cola do QR Code PIX (EMV / BR Code).
data.external_refString | nullReferência externa informada na criação do pagamento.
data.metadataObjectDados extras informados na criação (chave-valor).

Exemplos de Webhooks

1. pix-in.waiting_payment

Enviado quando o QR Code é gerado e a transação está aguardando pagamento.

{
  "id": "evt_a1b2c3d4e5f6a1b2c3d4e5f6",
  "event": "pix-in.waiting_payment",
  "type": "pix-in",
  "created_at": "2026-02-15T07:08:22.567Z",
  "data": {
    "id": "7427a0dd-2c05-4e73-be21-b4809a77e35f",
    "status": "waiting_payment",
    "amount": 10000,
    "currency": "BRL",
    "fee": {
      "total_fee": 2800,
      "net_amount": 7200
    },
    "paid_at": null,
    "created_at": "2026-02-15T07:08:22.567Z",
    "customer": {
      "name": "João da Silva",
      "document": {
        "type": "CPF",
        "number": "12345678909"
      },
      "email": "[email protected]",
      "phone": "11987654321"
    },
    "pix": {
      "end_to_end_id": null,
      "qrcode": "00020101021226850014br.gov.bcb.pix2563qrcode.example.com/pix/ff552266..."
    },
    "external_ref": "pedido-123",
    "metadata": {
      "orderId": "123"
    }
  }
}

2. pix-in.paid

Enviado quando o pagamento é confirmado. Este é o evento mais importante — use-o para concluir pedidos e liberar produtos/serviços.

{
  "id": "evt_b2c3d4e5f6a1b2c3d4e5f6a1",
  "event": "pix-in.paid",
  "type": "pix-in",
  "created_at": "2026-02-15T07:09:26.615Z",
  "data": {
    "id": "7427a0dd-2c05-4e73-be21-b4809a77e35f",
    "status": "paid",
    "amount": 10000,
    "currency": "BRL",
    "fee": {
      "total_fee": 2800,
      "net_amount": 7200
    },
    "paid_at": "2026-02-15T07:09:26.615Z",
    "created_at": "2026-02-15T07:08:22.567Z",
    "customer": {
      "name": "João da Silva",
      "document": {
        "type": "CPF",
        "number": "12345678909"
      },
      "email": "[email protected]",
      "phone": "11987654321"
    },
    "pix": {
      "end_to_end_id": "E20018183202602150709s669oDbAGB1",
      "qrcode": "00020101021226850014br.gov.bcb.pix2563qrcode.example.com/pix/ff552266..."
    },
    "external_ref": "pedido-123",
    "metadata": {
      "orderId": "123"
    }
  }
}
📘

Nota

Quando o status muda para paid, o valor líquido (data.fee.net_amount) é creditado automaticamente no saldo da sua conta. Neste exemplo, R$ 72,00 foram creditados (R$ 100,00 - R$ 28,00 de taxa).

3. pix-in.expired

Enviado quando o QR Code expira sem que o pagamento tenha sido realizado.

{
  "id": "evt_c3d4e5f6a1b2c3d4e5f6a1b2",
  "event": "pix-in.expired",
  "type": "pix-in",
  "created_at": "2026-02-17T00:00:01.000Z",
  "data": {
    "id": "7427a0dd-2c05-4e73-be21-b4809a77e35f",
    "status": "expired",
    "amount": 10000,
    "currency": "BRL",
    "fee": null,
    "paid_at": null,
    "created_at": "2026-02-15T07:08:22.567Z",
    "customer": {
      "name": "João da Silva",
      "document": {
        "type": "CPF",
        "number": "12345678909"
      },
      "email": "[email protected]",
      "phone": "11987654321"
    },
    "pix": {
      "end_to_end_id": null,
      "qrcode": "00020101021226850014br.gov.bcb.pix2563qrcode.example.com/pix/ff552266..."
    },
    "external_ref": "pedido-123",
    "metadata": {
      "orderId": "123"
    }
  }
}

4. pix-in.refunded

Enviado quando um reembolso é realizado após o pagamento ter sido confirmado.

{
  "id": "evt_d4e5f6a1b2c3d4e5f6a1b2c3",
  "event": "pix-in.refunded",
  "type": "pix-in",
  "created_at": "2026-02-16T10:30:00.000Z",
  "data": {
    "id": "7427a0dd-2c05-4e73-be21-b4809a77e35f",
    "status": "refunded",
    "amount": 10000,
    "currency": "BRL",
    "fee": {
      "total_fee": 2800,
      "net_amount": 7200
    },
    "paid_at": "2026-02-15T07:09:26.615Z",
    "created_at": "2026-02-15T07:08:22.567Z",
    "customer": {
      "name": "João da Silva",
      "document": {
        "type": "CPF",
        "number": "12345678909"
      },
      "email": "[email protected]",
      "phone": "11987654321"
    },
    "pix": {
      "end_to_end_id": "E20018183202602150709s669oDbAGB1",
      "qrcode": null
    },
    "external_ref": "pedido-123",
    "metadata": {
      "orderId": "123"
    }
  }
}
🚧

Atenção

Quando o status muda para refunded, o valor líquido que havia sido creditado anteriormente é debitado do saldo da sua conta.


Headers HTTP Enviados

Cada notificação de webhook inclui os seguintes headers HTTP:

HeaderValorDescrição
Content-Typeapplication/jsonFormato do corpo da requisição.
X-Webhook-Sourcevoidpayments-apiIdentifica a origem da notificação.
X-Transaction-IdUUID da transaçãoID da transação no nosso sistema.
X-EventEx: pix-in.paidTipo do evento enviado.
Idempotency-KeyID do evento (evt_*)Chave única para deduplicação. Mesmo valor em retentativas.

Exemplo de headers:

POST /seu-endpoint/webhook HTTP/1.1
Host: seu-dominio.com
Content-Type: application/json
X-Webhook-Source: voidpayments-api
X-Transaction-Id: 7427a0dd-2c05-4e73-be21-b4809a77e35f
X-Event: pix-in.paid
Idempotency-Key: evt_b2c3d4e5f6a1b2c3d4e5f6a1

Política de Retry

Como funciona

Nosso sistema garante entrega pelo menos uma vez (at-least-once). Se a entrega de um webhook falhar, tentaremos enviá-lo novamente automaticamente com backoff exponencial.

O que é considerado falha:

  • Resposta HTTP com código 5xx
  • Timeout (sem resposta em 10 segundos)
  • Erro de rede (conexão recusada, DNS não resolvido, etc.)

O que é considerado sucesso:

  • Resposta HTTP com código 2xx (200-299)
⚠️

Atenção

Respostas HTTP 4xx (exceto 429) não são retentadas, pois indicam um problema no seu endpoint que precisa ser corrigido.

Sequência de retry

TentativaIntervalo aproximadoAcumulado
Imediata
~1 minuto~1 min
~5 minutos~6 min
~15 minutos~21 min
~1 hora~1h21

Após 5 tentativas sem sucesso, o webhook é movido para uma fila de mensagens mortas (Dead Letter Queue) e pode ser consultado via endpoint GET /webhooks?transactionId={id} para auditoria.


Boas Práticas de Integração

1. Implemente idempotência

Como garantimos entrega pelo menos uma vez, seu endpoint pode receber o mesmo evento mais de uma vez. Use o header Idempotency-Key para verificar se o evento já foi processado:

app.post('/webhook', async (req, res) => {
  const idempotencyKey = req.headers['idempotency-key'];
  
  // Verificar se já processou este evento
  const alreadyProcessed = await cache.get(`webhook:${idempotencyKey}`);
  if (alreadyProcessed) {
    return res.status(200).json({ message: 'Already processed' });
  }
  
  // Processar o evento
  const { event, data } = req.body;
  
  if (event === 'pix-in.paid') {
    await processPaymentConfirmation(data);
  }
  
  // Marcar como processado (TTL de 24h)
  await cache.set(`webhook:${idempotencyKey}`, true, 86400);
  
  return res.status(200).json({ message: 'OK' });
});

2. Responda rápido, processe depois

Retorne HTTP 200 o mais rápido possível e processe o evento de forma assíncrona:

app.post('/webhook', async (req, res) => {
  // Responder imediatamente
  res.status(200).json({ received: true });
  
  // Processar em background
  processWebhookAsync(req.body).catch(console.error);
});

3. Valide a origem

Verifique o header X-Webhook-Source para confirmar que a notificação veio da nossa API:

if (req.headers['x-webhook-source'] !== 'voidpayments-api') {
  return res.status(403).json({ error: 'Invalid source' });
}

Suporte

Em caso de dúvidas sobre a integração de webhooks, entre em contato com nossa equipe:

  • 📧 Email: [email protected]
  • 📖 API Reference: Consulte os endpoints GET /webhooks para verificar o histórico de notificações enviadas