EvoPay

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/ — campo callbackUrl
  • POST /v1/withdraw/ — campo callbackUrl
  • POST /v1/withdraw/qrcode — campo callbackUrl

Seu servidor deve responder com qualquer status HTTP 2xx para confirmar o recebimento.


Política de entrega

ParâmetroValor
Tentativas máximas5
BackoffExponencial, base 2 minutos + 50% de jitter
Timeout por tentativa10 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

CampoTipoDescrição
idstringID da transação
typeTransactionTypeDEPOSIT ou WITHDRAW
statusTransactionStatusStatus atual
amountnumberValor em reais
serviceFeeChargednumber | nullTaxa cobrada
clientReferencestring | nullReferência externa enviada na criação
cancellationReasonstring | nullMotivo do cancelamento
endToEndIdstring | nullID fim a fim Pix
paidAtstring | nullTimestamp do pagamento (ISO 8601)

Campos típicos por tipo

CampoDEPOSITWITHDRAW
qrCodeText / qrCodeUrl / qrCodeBase64Preenchidonull
generatedName / generatedDocument / generatedEmailPreenchido se informado na criaçãonull
payerName / payerDocument / payerInstitutionIspb / payerInstitutionNameFornecido pelo provedor quando disponívelFornecido pelo provedor quando disponível
receiverName / receiverDocument / receiverInstitutionIspb / receiverInstitutionNamenullPreenchido após liquidação
withdrawPixKey / withdrawPixTypenullPreenchido (saque via chave)
withdrawQrCodeTextnullPreenchido (saque via QR Code)

Campos de estorno

Preenchidos quando status é WAITING_FOR_REFUND ou REFUNDED.

CampoTipoDescrição
refundStatusRefundStatus | nullStatus do estorno
refundReasonRefundReason | nullMotivo do estorno
refundAmountnumber | nullValor estornado
refundEndToEndIdstring | nullID fim a fim do estorno
refundDescriptionstring | nullDescrição livre
refundedAtstring | nullTimestamp 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"
  }
}
CampoTipoDescrição
idstringID da infração
protocolstringProtocolo fornecido pelo provedor
statusInfractionStatusStatus da infração
typeInfractionTypeTipo da infração
reportDetailsstringDescrição do motivo
reportedByReportedTypeQuem reportou
analysisResultAnalysisResult | nullResultado da análise
analysisDetailsstring | nullJustificativa da decisão
reportedAtstringTimestamp do reporte (ISO 8601)
expiresAtstring | nullPrazo de resolução (ISO 8601)
createdAtstringTimestamp de criação (ISO 8601)
updatedAtstringTimestamp 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 (recipientId inexistente 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 percent da transação acima de 100%, ou soma dos splits fixed acima 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[]

CampoTipoDescrição
recipientIdstringID do usuário recebedor do split
recipientNamestring | nullNome do recebedor. null quando o split falhou antes de resolver quem é o recebedor
type"fixed" | "percent"Tipo do split configurado
valuenumberValor configurado (reais para fixed, percentual 0–100 para percent)
protectedboolean | nullnull quando type é fixed — só se aplica a percent
status"PENDING" | "EXECUTED" | "FAILED"Estado de execução do split
executedAmountnumber | nullValor efetivamente creditado ao recebedor. null quando o split não foi executado
failureReasonstring | nullMotivo textual da falha. null quando o split foi executado com sucesso
failureScope"structural" | "recipient" | nullstructural 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[]

CampoTipoDescrição
recipientIdstring | nullID do recebedor daquele split. null em falha estrutural — a entrada cobre o array de splits inteiro, não um recebedor específico
reasonstringMotivo da falha

Regra de cálculo (referência rápida)

  • type: fixed — o recebedor sempre recebe o valor cheio informado em value, em reais. Não existe variante protected para fixed.
  • 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 fixed e percent podem 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/.

EvoPay API Documentation