Webhooks
O sistema de webhooks da Pix Processamento envia notificações em tempo real sobre
mudanças de status das suas transações. Quando você cria uma transação
e fornece um callbackUrl, nosso sistema envia atualizações para essa
URL toda vez que houver mudança de status.
O que é um webhook (callback)
Um webhook (também chamado de callback) é uma requisição POST que a Pix Processamento envia para o seu servidor quando algo acontece. Ao contrário da API normal (onde você chama a Pix Processamento), aqui é o oposto: a Pix Processamento chama você.
Pensa numa cobrança Pix. Você criou ela, exibiu o QR ao cliente, e agora precisa saber quando o cliente paga. Duas opções:
- Polling, ficar perguntando a cada X segundos "já pagou? já pagou?" (custoso, lento, desnecessário).
- Webhook, deixar a Pix Processamento te avisar assim que o pagamento entrar (instantâneo, eficiente, recomendado).
Duas formas de receber
| Forma | Como configura | Assinatura | Filtro por evento |
|---|---|---|---|
callbackUrl na transação | Campo no body de cada POST | Não | Não, recebe toda mudança |
| Webhook cadastrado | Uma vez, em POST /user/webhooks | HMAC SHA-256 | Sim, pelo campo events |
As duas convivem. Se a transação tem callbackUrl e a conta tem webhook ativo, os dois recebem o mesmo payload.
Modo 1: callbackUrl na transação
A URL é informada a cada transação criada, no campo callbackUrl do body:
{
"amount": 99.90,
"callbackUrl": "https://seusite.com.br/webhooks/pix",
"clientReference": "pedido-2025-001"
}A Pix Processamento vai enviar o callback para essa URL toda vez que aquela transação mudar de status (PENDING → COMPLETED, COMPLETED → REFUNDED, etc).
Crie um endpoint público no seu servidor
Algum lugar acessível pela internet que aceite POST com JSON. Exemplos: https://seusite.com.br/webhooks/pix, https://api.suaempresa.com/pix/callback.
Durante desenvolvimento local, use túneis como ngrok ou Cloudflare Tunnel pra expor o localhost.
Passe a URL ao criar a transação
Em todo POST /pix, POST /withdraw, POST /internal-transfer, inclua o campo callbackUrl. Pode ser a mesma URL pra todos.
Implemente o handler
Receba o POST, leia o JSON, processe e responda 2xx em até 5 segundos. Veja exemplos em Receber Pix · passo 3.
Modo 2: webhook cadastrado
Registre a URL uma vez, escolha os eventos e ganhe assinatura HMAC. Não precisa repetir callbackUrl em cada transação.
Cadastre a URL
curl -X POST https://api.exemplo.processamento.com/v1/user/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seusite.com.br/webhooks/pix",
"events": ["TRANSACTION_COMPLETED", "TRANSACTION_REFUNDED"],
"generateSecret": true
}'A resposta traz o id e o secret. O secret aparece só nessa resposta, guarde num cofre de segredos.
Verifique a assinatura no handler
Todo disparo de webhook cadastrado chega com X-Callback-Event e, quando há secret, com X-Callback-Signature. Confira a assinatura antes de processar, veja Assinatura HMAC.
Opere o webhook
Pause com PATCH /user/webhooks/{id} e active: false, troque o secret com POST /user/webhooks/{id}/rotate-secret, audite um disparo em GET /user/webhooks/{id}/sent/{callbackId} e reenvie o que falhou com POST /user/callbacks/resend/webhook/{webhookId}.
Limite de 5 webhooks ativos por conta. Acima disso, criar ou reativar devolve 409 Conflict. A referência dos 8 endpoints está em Endpoints · Webhooks.
Eventos
Vale só para webhook cadastrado. Enviar events: [], ou omitir o campo, assina todos.
| Evento | Quando dispara |
|---|---|
TRANSACTION_PENDING | Transação criada e aguardando pagamento |
TRANSACTION_COMPLETED | Transação liquidada |
TRANSACTION_CANCELED | Transação cancelada |
TRANSACTION_WAITING_FOR_REFUND | Estorno solicitado, aguardando processamento |
TRANSACTION_REFUNDED | Estorno concluído |
TRANSACTION_EXPIRED | Cobrança expirou sem pagamento |
TRANSACTION_ERROR | Transação terminou em erro |
TRANSACTION_SUSPECTED_FRAUD | Transação marcada como suspeita de fraude |
TRANSACTION_SUSPECTED_FRAUD_REVERSAL | Marcação de suspeita de fraude revertida |
INFRACTION_CHANGED | Infração (MED) ligada a uma transação mudou de status |
Headers do disparo
| Header | Quando | Valor |
|---|---|---|
Content-Type | sempre | application/json |
X-Callback-Attempt | sempre | número da tentativa, começando em 1 |
X-Callback-Event | só em webhook cadastrado | o evento, ex. TRANSACTION_COMPLETED |
X-Callback-Signature | só em webhook cadastrado que tem secret | t=<unix>, v1=<hmac-sha256-hex> |
Assinatura HMAC
O valor de X-Callback-Signature tem duas partes: t, o timestamp Unix em segundos, e v1, o HMAC SHA-256 em hexadecimal calculado sobre a string <t>.<corpo cru da requisição> usando o secret como chave.
X-Callback-Signature: t=1746540312, v1=6f2c0e...9ab1Use o corpo cru (a string recebida), não o objeto reserializado: qualquer mudança de espaçamento ou de ordem de chaves muda o hash.
import crypto from 'node:crypto';
app.post(
'/webhooks/pix',
express.raw({ type: 'application/json' }),
(req, res) => {
const header = req.get('X-Callback-Signature') ?? '';
const parts = Object.fromEntries(
header.split(',').map((part) => part.trim().split('=')),
);
const expected = crypto
.createHmac('sha256', process.env.PIX_WEBHOOK_SECRET)
.update(`${parts.t}.${req.body.toString('utf8')}`)
.digest('hex');
const ok =
parts.v1?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!ok) return res.sendStatus(401);
res.sendStatus(200);
enqueue(JSON.parse(req.body.toString('utf8')), req.get('X-Callback-Event'));
},
);import hashlib, hmac, os
from flask import request, abort
@app.post("/webhooks/pix")
def pix_webhook():
header = request.headers.get("X-Callback-Signature", "")
parts = dict(p.strip().split("=", 1) for p in header.split(",") if "=" in p)
expected = hmac.new(
os.environ["PIX_WEBHOOK_SECRET"].encode(),
f'{parts.get("t", "")}.{request.get_data(as_text=True)}'.encode(),
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(parts.get("v1", ""), expected):
abort(401)
enqueue(request.get_json(), request.headers.get("X-Callback-Event"))
return "", 200Compare com função de tempo constante (timingSafeEqual, hmac.compare_digest). Rejeite também disparos com t muito antigo, uma janela de 5 minutos é um bom padrão contra replay.
Sistema de retry
Os webhooks da Pix Processamento têm um sistema robusto de retentativa que garante a entrega mesmo em falhas temporárias. A Pix Processamento reenvia até 72 vezes o mesmo callback com backoff exponencial e jitter, distribuindo melhor a carga e evitando picos de requisições.
Tempo de resposta: o webhook deve responder com HTTP 200 OK em
até 5 segundos. Se exceder esse tempo, o sistema considera timeout
e inicia o processo de retentativa.
Segurança
Para garantir integridade e segurança, restrinja o acesso ao seu endpoint de webhook. Solicite o IP oficial da Pix Processamento ao suporte e aceite callbacks apenas dessa origem.
Com webhook cadastrado, some a isso a assinatura HMAC:
o IP diz de onde veio, a assinatura prova que o corpo não foi adulterado.
Se o secret vazar, rotacione em
POST /user/webhooks/{id}/rotate-secret
e faça o deploy do novo valor antes, porque o anterior é invalidado na hora.
Campos do payload
Identificação
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID da transação |
clientReference | string | Referência externa que você forneceu |
virtualAccount | string | Subconta virtual (até 50 caracteres). Volta no callback para correlacionar lojas, filiais, marketplaces. |
callbackUrl | string | URL configurada para receber este webhook |
Status e valores
| Campo | Tipo | Descrição |
|---|---|---|
status | string | PENDING, COMPLETED, CANCELED, WAITING_FOR_REFUND, REFUNDED, EXPIRED, ERROR |
type | string | DEPOSIT, WITHDRAW |
method | string | PIX, BANK_SLIP, INTERNAL_TRANSFER |
amount | number | Valor em BRL |
serviceFeeCharged | number | Tarifa cobrada |
Cobrança gerada (depósito)
| Campo | Tipo | Descrição |
|---|---|---|
qrCodeText | string | Código Pix copia-e-cola |
qrCodeUrl | string | URL da imagem do QR Code |
qrCodeBase64 | string | Imagem do QR Code em formato Base64 |
generatedName | string | Nome de referência |
generatedDocument | string | CPF ou CNPJ |
generatedEmail | string | Email vinculado à transação |
Pagador
| Campo | Tipo | Descrição |
|---|---|---|
payerName | string | Nome do pagador |
payerDocument | string | Documento do pagador |
payerInstitutionIspb | string | ISPB do banco do pagador |
payerInstitutionName | string | Nome do banco do pagador |
payerAccountNumber | string | Conta Pix Processamento do pagador (6 dígitos). Preenchida quando a conta Pix Processamento é quem paga: saques e transferências internas. |
Recebedor
| Campo | Tipo | Descrição |
|---|---|---|
receiverName | string | Nome do destinatário |
receiverDocument | string | Documento do destinatário |
receiverInstitutionIspb | string | ISPB do banco do destinatário |
receiverInstitutionName | string | Nome do banco do destinatário |
receiverAccountNumber | string | Conta Pix Processamento do destinatário (6 dígitos). Preenchida quando a conta Pix Processamento é quem recebe: depósitos e transferências internas. |
Em saques, os demais campos
payer*descrevem a conta de liquidação do provedor, enquantopayerAccountNumberé a conta Pix Processamento que originou o saque. Para identificar uma transferência interna, usemethod: INTERNAL_TRANSFER, não a presença desses campos.
Saque via chave Pix
| Campo | Tipo | Descrição |
|---|---|---|
withdrawPixKey | string | Chave Pix usada no saque |
withdrawPixType | string | cpf, cnpj, phone, email, evp |
Liquidação e estorno
| Campo | Tipo | Descrição |
|---|---|---|
endToEndId | string | EndToEnd ID do Pix |
paidAt | string | Timestamp do pagamento (ISO 8601) |
cancellationReason | string | Motivo do cancelamento |
refundEndToEndId | string | EndToEnd ID do estorno |
refundAmount | string | Valor estornado |
refundStatus | string | PENDING, COMPLETED, CANCELED |
refundReason | string | Motivo do estorno |
refundDescription | string | Descrição do estorno |
refundedAt | string | Timestamp do estorno (ISO 8601) |
Timestamps
| Campo | Tipo | Descrição |
|---|---|---|
createdAt | string | Timestamp de criação (ISO 8601) |
updatedAt | string | Timestamp de atualização (ISO 8601) |
Infração (disputa Pix)
| Campo | Tipo | Descrição |
|---|---|---|
infraction | object | Detalhes da infração quando aberta (ver MED) |
Boas práticas
- Responda rápido: devolva
2xxem menos de 5s. Processe pesado em fila/worker, não no handler. - Idempotência: armazene
id+statuspara deduplicar. O mesmo callback pode chegar mais de uma vez (retentativa, mudanças sucessivas). - Use
clientReference: passe um identificador externo na criação da transação. Volta no callback e facilita correlacionar com seu pedido. - Restrinja por IP: aceite callbacks apenas do IP oficial da Pix Processamento.
- Valide a assinatura: em webhook cadastrado, rejeite com
401todo disparo cujaX-Callback-Signaturenão bater.
Inspeção e reenvio
A API expõe a lista completa de callbacks enviados:
GET /user/callbacks, lista paginadaGET /user/callbacks/{id}, detalhesPOST /user/callbacks/resend/{transactionId}, reenviar callback de uma transaçãoPOST /user/callbacks/resend, reenvio em lotePOST /user/callbacks/resend/webhook/{webhookId}, reenvia tudo que falhou num webhook cadastrado
Para webhook cadastrado há ainda a contagem e o detalhe do disparo:
GET /user/webhooks/sent/quantity, quantos disparos saíramGET /user/webhooks/{id}/sent/{callbackId}, payload, status e resposta de um disparo
Infrações (MED)
O MED é o processo do Bacen para contestar Pix em casos de fraude ou erro do pagador. Quando uma cobrança recebida vira disputa, a Pix Processamento cria uma infração e você tem prazo curto para responder com defesa.
Boas práticas
Padrões testados em produção que separam uma integração que dura uma semana de uma que aguenta produção. Idempotência, multi-tenant, callbacks, paginação, dinheiro, segurança, tratamento de erros e checklist final.