Webhooks
A EvoPay envia uma notificação HTTP POST para a callbackUrl informada na criação da transação sempre que o status é atualizado.
Configuração
A callbackUrl é opcional e informada nos endpoints de criação:
POST /v1/pix/— campocallbackUrlPOST /v1/withdraw/— campocallbackUrlPOST /v1/withdraw/qrcode— campocallbackUrl
Seu servidor deve responder com qualquer status HTTP 2xx para confirmar o recebimento.
Política de entrega
| Parâmetro | Valor |
|---|---|
| Tentativas máximas | 5 |
| Backoff | Exponencial, base 2 minutos + 50% de jitter |
| Timeout por tentativa | 10 segundos |
Após 5 falhas consecutivas o reenvio para. Use Reenvio de callbacks em lote ou Reenvio de callback por transação para reenviar manualmente.
Headers enviados
Content-Type: application/json
User-Agent: Callback-Service/1.0
X-Callback-Attempt: <n>
X-Callback-Attempt começa em 0 na primeira tentativa e vai até 4 na quinta.
Payload
DEPOSIT e WITHDRAW recebem o mesmo schema. Os campos null variam conforme o status e o tipo da transação.
{
"id": "EPB1694C2C35E94053874D53B1",
"type": "DEPOSIT",
"status": "COMPLETED",
"amount": 100.00,
"serviceFeeCharged": 2.50,
"clientReference": "pedido-123",
"qrCodeText": "00020101...",
"qrCodeUrl": "https://...",
"qrCodeBase64": "iVBORw0KGgo...",
"generatedName": "João Silva",
"generatedDocument": "12345678901",
"generatedEmail": "joao@email.com",
"payerName": "João Silva",
"payerDocument": "12345678901",
"payerInstitutionIspb": "60746948",
"payerInstitutionName": "Itaú",
"receiverName": null,
"receiverDocument": null,
"receiverInstitutionIspb": null,
"receiverInstitutionName": null,
"withdrawPixKey": null,
"withdrawPixType": null,
"withdrawQrCodeText": null,
"endToEndId": "E60746948...",
"cancellationReason": null,
"paidAt": "2024-01-01T12:05:00.000Z",
"refundEndToEndId": null,
"refundAmount": null,
"refundStatus": null,
"refundReason": null,
"refundDescription": null,
"refundedAt": null,
"createdAt": "2024-01-01T12:00:00.000Z",
"updatedAt": "2024-01-01T12:05:00.000Z"
}
Campos principais
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID da transação |
type | TransactionType | DEPOSIT ou WITHDRAW |
status | TransactionStatus | Status atual |
amount | number | Valor em reais |
serviceFeeCharged | number | null | Taxa cobrada |
clientReference | string | null | Referência externa enviada na criação |
cancellationReason | string | null | Motivo do cancelamento |
endToEndId | string | null | ID fim a fim Pix |
paidAt | string | null | Timestamp do pagamento (ISO 8601) |
Campos típicos por tipo
| Campo | DEPOSIT | WITHDRAW |
|---|---|---|
qrCodeText / qrCodeUrl / qrCodeBase64 | Preenchido | null |
generatedName / generatedDocument / generatedEmail | Preenchido se informado na criação | null |
payerName / payerDocument / payerInstitutionIspb / payerInstitutionName | Fornecido pelo provedor quando disponível | Fornecido pelo provedor quando disponível |
receiverName / receiverDocument / receiverInstitutionIspb / receiverInstitutionName | null | Preenchido após liquidação |
withdrawPixKey / withdrawPixType | null | Preenchido (saque via chave) |
withdrawQrCodeText | null | Preenchido (saque via QR Code) |
Campos de estorno
Preenchidos quando status é WAITING_FOR_REFUND ou REFUNDED.
| Campo | Tipo | Descrição |
|---|---|---|
refundStatus | RefundStatus | null | Status do estorno |
refundReason | RefundReason | null | Motivo do estorno |
refundAmount | number | null | Valor estornado |
refundEndToEndId | string | null | ID fim a fim do estorno |
refundDescription | string | null | Descrição livre |
refundedAt | string | null | Timestamp do estorno (ISO 8601) |
Campo infraction (opcional)
Presente apenas quando o webhook é disparado por uma atualização de infração Pix associada à transação. Em callbacks normais de depósito e saque, este campo não aparece no payload.
{
"id": "EPB1694C2C35E94053874D53B1",
"type": "DEPOSIT",
"status": "WAITING_FOR_REFUND",
...
"infraction": {
"id": "uuid",
"protocol": "PROTOCOL123",
"status": "OPEN",
"type": "FRAUD",
"reportDetails": "Transação não reconhecida pelo pagador",
"reportedBy": "DEBITED_PARTICIPANT",
"analysisResult": null,
"analysisDetails": null,
"reportedAt": "2024-01-01T13:00:00.000Z",
"expiresAt": "2024-02-01T13:00:00.000Z",
"createdAt": "2024-01-01T13:00:00.000Z",
"updatedAt": "2024-01-01T13:00:00.000Z"
}
}
| Campo | Tipo | Descrição |
|---|---|---|
id | string | ID da infração |
protocol | string | Protocolo fornecido pelo provedor |
status | InfractionStatus | Status da infração |
type | InfractionType | Tipo da infração |
reportDetails | string | Descrição do motivo |
reportedBy | ReportedType | Quem reportou |
analysisResult | AnalysisResult | null | Resultado da análise |
analysisDetails | string | null | Justificativa da decisão |
reportedAt | string | Timestamp do reporte (ISO 8601) |
expiresAt | string | null | Prazo de resolução (ISO 8601) |
createdAt | string | Timestamp de criação (ISO 8601) |
updatedAt | string | Timestamp da última atualização (ISO 8601) |
Campos splits e splitWarnings (opcional)
Presentes apenas quando a transação original foi criada com o campo splits preenchido em POST /pix/. Para transações sem splits, o payload permanece idêntico ao formato acima — nenhum campo novo aparece, nem vazio.
O split é validado e persistido na criação da transação, mas executado só quando este webhook é disparado (confirmação do pagamento). Duas classes de falha:
- Falha de identidade (
recipientIdinexistente ou inativo): só aquele split específico falha. Os demais splits válidos executam normalmente, e o repasse ao seller nunca é afetado. - Falha estrutural (soma dos splits
percentda transação acima de 100%, ou soma dos splitsfixedacima do valor líquido disponível): todo o array de splits é rejeitado — tudo ou nada, diferente da falha de identidade, que é parcial. Nenhum split executa, e o valor líquido cheio é creditado ao seller.
Exemplo com um split executado e um rejeitado por falha de identidade:
{
"id": "EPB1694C2C35E94053874D53B1",
"type": "DEPOSIT",
"status": "COMPLETED",
"amount": 100.00,
...
"splits": [
{
"recipientId": "EPA1B2C3D4E5F60718293A4B5C",
"recipientName": "Maria Souza",
"type": "percent",
"value": 10,
"protected": false,
"status": "EXECUTED",
"executedAmount": 9.75,
"failureReason": null,
"failureScope": null
},
{
"recipientId": "EPZZZ000000000000000000ZZ",
"recipientName": null,
"type": "fixed",
"value": 5,
"protected": null,
"status": "FAILED",
"executedAmount": null,
"failureReason": "Recebedor não encontrado",
"failureScope": "recipient"
}
],
"splitWarnings": [
{
"recipientId": "EPZZZ000000000000000000ZZ",
"reason": "Recebedor não encontrado"
}
]
}
Exemplo de falha estrutural — soma dos splits percent excede 100%, array inteiro rejeitado, splitWarnings vem com uma única entrada e recipientId: null:
{
"splits": [
{
"recipientId": "EPA1B2C3D4E5F60718293A4B5C",
"recipientName": null,
"type": "percent",
"value": 60,
"protected": false,
"status": "FAILED",
"executedAmount": null,
"failureReason": "Soma dos splits percentuais da transação excede 100% — nenhum split foi aplicado, valor integral creditado ao seller",
"failureScope": "structural"
},
{
"recipientId": "EPB2C3D4E5F60718293A4B5C1",
"recipientName": null,
"type": "percent",
"value": 50,
"protected": false,
"status": "FAILED",
"executedAmount": null,
"failureReason": "Soma dos splits percentuais da transação excede 100% — nenhum split foi aplicado, valor integral creditado ao seller",
"failureScope": "structural"
}
],
"splitWarnings": [
{
"recipientId": null,
"reason": "Soma dos splits percentuais da transação excede 100% — nenhum split foi aplicado, valor integral creditado ao seller"
}
]
}
Campos de splits[]
| Campo | Tipo | Descrição |
|---|---|---|
recipientId | string | ID do usuário recebedor do split |
recipientName | string | null | Nome do recebedor. null quando o split falhou antes de resolver quem é o recebedor |
type | "fixed" | "percent" | Tipo do split configurado |
value | number | Valor configurado (reais para fixed, percentual 0–100 para percent) |
protected | boolean | null | null quando type é fixed — só se aplica a percent |
status | "PENDING" | "EXECUTED" | "FAILED" | Estado de execução do split |
executedAmount | number | null | Valor efetivamente creditado ao recebedor. null quando o split não foi executado |
failureReason | string | null | Motivo textual da falha. null quando o split foi executado com sucesso |
failureScope | "structural" | "recipient" | null | structural quando a falha derrubou o array inteiro (config errada); recipient quando é específica daquele recebedor (inexistente/inativo); null quando o split foi executado |
Campos de splitWarnings[]
| Campo | Tipo | Descrição |
|---|---|---|
recipientId | string | null | ID do recebedor daquele split. null em falha estrutural — a entrada cobre o array de splits inteiro, não um recebedor específico |
reason | string | Motivo da falha |
Regra de cálculo (referência rápida)
type: fixed— o recebedor sempre recebe o valor cheio informado emvalue, em reais. Não existe varianteprotectedparafixed.type: percent,protected: true— o percentual incide sobre o valor bruto da transação. O seller absorve a taxa EvoPay sozinho.type: percent,protected: false(padrão) — o percentual incide sobre o valor líquido (bruto menos a taxa EvoPay).- Splits
fixedepercentpodem coexistir na mesma transação — cada um calcula sobre sua própria base, em paralelo, não em cascata.
Risco aceito, não é bug: com protected: true e percentual alto (até 100%), o seller pode ficar com saldo negativo naquela transação específica — o split incide sobre o bruto e a taxa EvoPay é descontada por fora, independente do split. Quem configura o split assume essa consequência.
Regras completas de cálculo, validação e comportamento de erro em POST /pix/.