Devoluções
Referência
Devolver Pix e estornar cartão são processos diferentes. A devolução Pix depende do Bacen e costuma ficar pendente até a confirmação assíncrona; o estorno de cartão depende da adquirente e pode confirmar na hora. Este guia explica os dois fluxos, os campos que os diferenciam e o que muda na cobrança original.
POST /v1/wallet/refunds e GET /v1/wallet/refunds. Não existe uma rota separada para estorno de cartão. O que você envia no body decide qual caminho a API executa.Um endpoint, dois fluxos
A API decide o fluxo pelo campo identificador que você envia, não por um parâmetro de tipo:
| Você envia | Fluxo executado |
|---|---|
endToEndId | Devolução Pix |
chargeId (de uma cobrança de cartão) | Estorno de cartão |
chargeId (de uma cobrança Pix) | Devolução Pix |
Devolução Pix
A devolução Pix parte do endToEndId da transação original e é enviada ao Banco Central via Celcoin. Ela nasce quase sempre como PROCESSING. A confirmação chega depois, de forma assíncrona, pelo webhook.
| Campo | Obrigatório | Descrição |
|---|---|---|
endToEndId | Sim | EndToEndId da transação Pix original recebida. |
amount | Sim | Valor a devolver, parcial ou total, em reais (ex.: 10.00). |
reason | Sim | Um de: BANK_ERROR, FRAUD, CUSTOMER_REQUEST, PIX_CHANGE_ERROR. |
chargeId | Não | ID da cobrança associada, se você já tiver. Acelera a busca. |
accountId | Não | Número da subconta. Se omitido, opera na conta principal. |
{
"endToEndId": "E003603052026032511186a4f4cdf139",
"amount": 1.00,
"reason": "CUSTOMER_REQUEST"
}{
"refundId": "ref_1774437918293_jm2hen5y7",
"status": "PROCESSING",
"amount": 1,
"reason": "CUSTOMER_REQUEST",
"endToEndId": "E003603052026032511186a4f4cdf139",
"returnIdentification": "D13935893202603251125zbRSLI3lqPH",
"chargeId": "cha_1774437468463_4hj927ips",
"createdAt": "2026-03-25T11:25:18.293Z"
}Se a subconta de origem não tiver saldo suficiente, a ValidaPay adianta o valor da conta principal para a subconta antes de enviar a devolução ao Bacen, e registra a dívida internamente. Na conta principal, saldo insuficiente sem subconta de origem retorna INSUFFICIENT_BALANCE.
Estorno de cartão
O estorno de cartão parte do chargeId de uma cobrança CREDIT_CARD processada por um provedor com estorno suportado (Malga ou Marlim) e cujo status ainda permita estorno (paga, autorizada ou já parcialmente estornada). O provedor pode confirmar na hora, retornando CONFIRMED com success: true, ou deixar PROCESSING para confirmar depois.
| Campo | Obrigatório | Descrição |
|---|---|---|
chargeId | Sim | ID da cobrança de cartão a estornar. |
amount | Sim | Valor a estornar, parcial ou total, em reais (ex.: 100.00). |
reason | Sim | Um de: BANK_ERROR, FRAUD, CUSTOMER_REQUEST, PIX_CHANGE_ERROR. Na prática é obrigatório: sem ele, a API recusa com INVALID_REASON. |
accountId | Não | Número da subconta. Se omitido, opera na conta principal. |
{
"chargeId": "cha_1774530966959_frgj3ptax",
"amount": 100.00,
"reason": "CUSTOMER_REQUEST"
}{
"refundId": "ref_1774531490865_bq4e8v12x",
"status": "CONFIRMED",
"success": true,
"amount": 100,
"reason": "CUSTOMER_REQUEST",
"chargeId": "cha_1774530966959_frgj3ptax",
"providerChargeId": "prov_ch_9f8a7b6c",
"paymentType": "CREDIT_CARD",
"createdAt": "2026-03-26T13:24:52.106Z"
}Campos da resposta
A criação (201) e a consulta (200) devolvem essencialmente o mesmo formato. A consulta apenas acrescenta accountId, splitReversals e updatedAt.
| Campo | Descrição |
|---|---|
refundId | Identificador único da devolução/estorno. Use para consultar o status depois. |
status | PROCESSING, CONFIRMED ou ERROR. |
success | true quando status é CONFIRMED (atalho para não comparar string). |
amount | Valor devolvido/estornado nesta operação. |
reason | Motivo enviado na criação. |
chargeId | Cobrança original associada, quando identificada. |
originalEndToEndId | Só na devolução Pix: EndToEndId da transação original. |
returnIdentification | Só na devolução Pix: EndToEndId da devolução, gerado pelo banco. |
providerChargeId | Só no estorno de cartão: ID da cobrança no provedor (Malga/Marlim). |
paymentType | CREDIT_CARD no estorno de cartão; null na devolução Pix. |
splitReversals | Recolhimento proporcional de cada destinatário do split, quando a cobrança original teve split. |
error | Código de erro do provedor/banco quando status é ERROR (ex.: MD06). |
Precedência da consulta por GET: refundId > returnIdentification > endToEndId > chargeId. Sem nenhum identificador, retorna o histórico paginado da conta (com filtros de status e data).
Status da devolução
| Status | Significado |
|---|---|
PROCESSING | Devolução/estorno enviado, aguardando confirmação do banco ou do provedor de cartão. |
CONFIRMED | Valor devolvido/estornado com sucesso. No cartão, pode chegar direto nesse status se o provedor confirmar na hora. |
ERROR | O banco/provedor recusou a devolução. O campo error traz o código retornado (ex.: MD06). |
Valor parcial e total
- Os dois fluxos aceitam devolução parcial: envie em
amountsó o quanto quer devolver. - Cada devolução soma em
refundedAmountna cobrança original; quando o acumulado atinge o valor da cobrança, o status dela viraREFUNDED. Antes disso ficaPARTIALLY_REFUNDED. - Pedir mais do que ainda resta devolver retorna
REFUND_AMOUNT_EXCEEDED. - Não há prazo próprio da API para solicitar devolução ou estorno. A única checagem de tempo é a que o emissor do cartão ou o arranjo Pix aplicam do lado deles.
Split e devolução
Quando a cobrança original teve split, a confirmação da devolução Pix recolhe, proporcionalmente, a mesma fração do valor devolvido de cada destinatário do split, na mesma razão entre o valor devolvido e o valor total da cobrança. Se um destinatário não tiver saldo suficiente no momento, o recolhimento dele vira uma dívida (status: "PENDING" com debtId) em vez de ser debitado na hora.
Esse recolhimento aparece no array splitReversals ao consultar a devolução:
{
"refundId": "ref_1774531490865_bq4e8v12x",
"accountId": "429131212",
"status": "CONFIRMED",
"success": true,
"amount": 100.00,
"reason": "CUSTOMER_REQUEST",
"chargeId": "cha_1774530966959_frgj3ptax",
"originalEndToEndId": "E0036030520260326132336e2f8787c4",
"returnIdentification": "D13935893202603261324C5jA3zE3V6J",
"providerChargeId": null,
"paymentType": null,
"splitReversals": [
{ "accountNumber": "459013777", "amount": 30.00, "status": "REVERSED" },
{ "accountNumber": "470084294", "amount": 20.00, "status": "PENDING", "debtId": "debt_1774539002481_ab12cd34e" }
],
"error": null,
"createdAt": "2026-03-26T13:24:52.106Z",
"updatedAt": "2026-03-26T13:24:57.553Z"
}No estorno de cartão não há esse recolhimento automático do split. O valor sai só da cobrança original.
Erros comuns
| code | Status | Quando acontece |
|---|---|---|
MISSING_REFUND_IDENTIFIER | 400 | Nem endToEndId nem um chargeId de cartão elegível foram enviados. |
MISSING_END_TO_END_ID | 400 | Faltou endToEndId ao tentar devolução Pix. |
MISSING_CHARGE_ID | 400 | Faltou chargeId ao tentar estorno de cartão. |
REFUND_NOT_SUPPORTED_FOR_CHARGE | 400 | chargeId aponta para uma cobrança que não é de cartão suportado nem tem endToEndId informado. |
INVALID_CHARGE_TYPE | 400 | A cobrança não é CREDIT_CARD de um provedor com estorno suportado (Malga/Marlim). |
MISSING_PROVIDER_CHARGE_ID | 400 | Cobrança de cartão sem transactionId do provedor: não há o que estornar. |
CHARGE_NOT_REFUNDABLE | 400 | Status atual da cobrança não permite estorno (ex.: ainda não paga). |
CHARGE_NOT_FOUND | 404 | chargeId informado não existe. |
INVALID_AMOUNT | 400 | amount ausente, zero ou negativo. |
REFUND_AMOUNT_EXCEEDED | 400 | Valor solicitado passa do que ainda pode ser devolvido nessa cobrança. |
INVALID_REASON | 400 | reason ausente ou fora de BANK_ERROR, FRAUD, CUSTOMER_REQUEST, PIX_CHANGE_ERROR. |
INSUFFICIENT_BALANCE | 400 | Saldo insuficiente na conta principal para devolver (sem subconta de origem para adiantar). |
SUB_ACCOUNT_NOT_FOUND | 404 | accountId informado não corresponde a nenhuma subconta. |
OWNERSHIP_MISMATCH | 401 | A subconta (accountId) ou a cobrança não pertence à conta autenticada. |
REFUND_NOT_FOUND | 404 | refundId ou returnIdentification informado não existe ou não é legível pela conta autenticada. |