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 | Quando o Pix é de uma cobrança ValidaPay, não envie: a devolução sai da conta dona da cobrança, e um accountId diferente dela retorna CHARGE_NOT_FOUND. Só indica a subconta quando o Pix recebido não tem cobrança na ValidaPay. Se omitido nesse caso, usa a conta principal. |
{
"endToEndId": "E003603052026032511186a4f4cdf139",
"amount": 1.00,
"reason": "CUSTOMER_REQUEST"
}{
"refundId": "ref_1774437918293_jm2hen5y7",
"status": "PROCESSING",
"amount": 1,
"reason": "CUSTOMER_REQUEST",
"endToEndId": "E003603052026032511186a4f4cdf139",
"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ão envie. O estorno sempre acontece na conta dona da cobrança, a que a criou. Se vier uma conta diferente dela, a API retorna CHARGE_NOT_FOUND. |
{
"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"
}O estorno sempre acontece na conta dona da cobrança, a que a criou. Não envie accountId: uma cobrança criada na conta principal com split para uma subconta continua sendo da conta principal, e enviar o número da subconta retorna CHARGE_NOT_FOUND.
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. |
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 > 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",
"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"
}Split no estorno de cartão
No cartão, a divisão do split é feita na adquirente, no momento do pagamento: cada destinatário passa a ter a sua parte na agenda de recebíveis, com a mesma data de recebimento da conta dona. Por isso o estorno não debita saldo em conta das subcontas, e o array splitReversals vem vazio.
- Estorno total: a transação inteira é estornada ao portador do cartão e a parte de cada conta (dona e destinatários) é cancelada na agenda de recebíveis. Feito antes da data de recebimento, nenhuma das contas tem débito no saldo, porque o valor ainda não foi repassado.
- Estorno parcial: cada destinatário devolve a fração do valor estornado proporcional à parte dele sobre o valor bruto da cobrança, e o restante sai da conta dona. Quando o estorno parcial com split não é suportado para a cobrança, a API retorna
CARD_SPLIT_PARTIAL_REFUND_UNSUPPORTEDe só o estorno total é aceito.
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. |
CHARGE_WITHOUT_END_TO_END_ID | 400 | Devolução pedida por chargeId de uma cobrança sem endToEndId: o Pix ainda não foi pago ou a cobrança nã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 não existe, pertence a outra conta ou veio com um accountId diferente da conta dona da cobrança. |
CARD_SPLIT_PARTIAL_REFUND_UNSUPPORTED | 400 | Estorno parcial de cartão com split ainda não suportado para a cobrança. Faça o estorno total. |
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 | Devolução de Pix sem cobrança na ValidaPay: o accountId não corresponde a nenhuma subconta. |
OWNERSHIP_MISMATCH | 401 | Devolução de Pix sem cobrança na ValidaPay: a subconta (accountId) não pertence à conta autenticada. |