Para estornar um Pix pela API, você chama POST /api/v1/charges/{id}/refund com o id da cobrança paga. A API pede ao PSP a devolução do valor total ao pagador, por Pix, e responde 202 com o estorno em pending. Quando o dinheiro volta de fato, chega o webhook transaction.refunded e a cobrança passa a refunded. As regras abaixo seguem a documentação da API. Para o restante da integração, veja o guia da API Pix.
Regras do estorno
| Item | Regra |
|---|---|
| Valor | Total da cobrança. Não há estorno parcial na API. |
| Quantas vezes | Uma por cobrança. Repetir o POST devolve o mesmo estorno. |
| Quais cobranças | Só as que estão com status paid. |
| Prazo | Até 90 dias após o pagamento. |
| Motivo | reason opcional, até 140 caracteres. O pagador pode ver esse texto. |
| Saldo | Enquanto o estorno está pending, o valor líquido fica retido do saldo disponível. |
Como pedir o estorno
curl -X POST https://app.xflowpayments.com/api/v1/charges/clx.../refund \
-u "pk_live_...:sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "reason": "Cliente desistiu" }'Resposta 202:
{
"id": "clx...",
"chargeId": "clx...",
"livemode": true,
"status": "pending",
"amountCents": 1990,
"reason": "Cliente desistiu",
"createdAt": "2026-10-25T13:00:00.000Z",
"completedAt": null,
"failureReason": null
}O mesmo pedido em Node.js, com fetch:
const cred = Buffer.from(`${process.env.XFLOW_PUBLIC_KEY}:${process.env.XFLOW_SECRET_KEY}`).toString("base64");
const res = await fetch(`https://app.xflowpayments.com/api/v1/charges/${chargeId}/refund`, {
method: "POST",
headers: { Authorization: `Basic ${cred}`, "Content-Type": "application/json" },
body: JSON.stringify({ reason: "Cliente desistiu" }),
});
const estorno = await res.json();
// 202 -> estorno.status === "pending"; 200 -> estorno.status === "completed"Exemplos completos de cliente HTTP estão em API Pix em Node.js, PHP e Python.
O estorno é assíncrono
202 com status: "pending" significa que o PSP aceitou o pedido. O dinheiro ainda não voltou. A conclusão vem por webhook:
transaction.refunded: a devolução ao pagador concluiu. A cobrança passa arefunded.transaction.refund_failed: o PSP recusou. A cobrança continuapaide o valor retido volta ao seu saldo.
Há um caso em que a devolução conclui na hora, quando o pagador está na mesma instituição. Aí a resposta já vem 200 com status: "completed". Trate os dois códigos como sucesso do pedido e use o status para decidir o próximo passo.
Um estorno que terminou em failed pode ser pedido de novo. A validação da assinatura dos eventos está em webhook Pix.
Consultar o estorno
Use GET /api/v1/charges/{id}/refund. Ele devolve o mesmo objeto da criação, ou 404 se a cobrança não tem estorno. O campo refund de GET /api/v1/charges/{id} traz a mesma informação, ou null sem estorno. Esse campo aparece só na consulta por id, não na listagem.
| Status do estorno | Significado |
|---|---|
pending |
Pedido aceito pelo PSP, devolução em processamento. Valor retido do saldo. |
completed |
Devolução concluída. completedAt preenchido. |
failed |
Devolução recusada. failureReason explica. Pode ser pedido de novo. |
Fluxo recomendado no seu sistema
- Confira a cobrança. Consulte
GET /api/v1/charges/{id}e verifique se ostatusépaide se opaidAtestá dentro dos 90 dias. Isso evita um422previsível. - Peça o estorno com um
reasonclaro, já que o pagador pode ver esse texto. - Marque o pedido como "estorno solicitado", e não como estornado. Na resposta
202, o dinheiro ainda não voltou. - Feche pelo webhook. Em
transaction.refunded, marque como estornado. Emtransaction.refund_failed, volte o pedido para pago e decida se pede de novo. - Trate a falta de saldo. Se vier
insufficient_balance, o camposhortfallCentsdiz quanto falta. Mostre esse valor a quem opera o estorno.
Se a resposta já vier 200 com status: "completed", pule para o fim e marque o pedido como estornado. Como repetir o POST na mesma cobrança devolve o mesmo estorno, um retry depois de uma queda de conexão não gera devolução em dobro.
Quando o estorno é recusado
| HTTP | Código | Causa | O que fazer |
|---|---|---|---|
| 422 | charge_not_refundable |
A cobrança não está paid. |
Confira o status com GET /charges/{id}. |
| 422 | refund_window_expired |
Mais de 90 dias desde o pagamento. | O estorno pela API não está mais disponível. |
| 422 | insufficient_balance |
O saldo disponível não cobre o estorno. O corpo traz shortfallCents. |
Aguarde saldo suficiente e tente de novo. |
| 422 | refund_not_supported |
O provedor desta cobrança não oferece estorno via API. | Fale com o suporte, citando o request_id. |
| 502 | refund_failed |
O PSP recusou ou não respondeu. Nada fica retido. | Tente de novo mais tarde. |
Toda resposta, de sucesso ou erro, traz um request_id. Ele localiza a chamada em Integrações > Logs da API. A tabela geral está em erros da API Pix.
Estorno no sandbox
Com chave de teste (pk_test_), o estorno conclui na hora, sem PSP, e a cobrança de teste passa a refunded. Assim você testa o fluxo inteiro: criar a cobrança, simular o pagamento com POST /api/v1/test/charges/{id}/pay e estornar. Teste também os desvios: pedir estorno de uma cobrança que ainda está pending deve dar 422 charge_not_refundable, e repetir o pedido na mesma cobrança deve devolver o mesmo estorno. O passo a passo está em sandbox da API Pix.
Estorno, devolução e MED
No vocabulário do Pix, o estorno se chama devolução. O Manual de Padrões para Iniciação do Pix do Banco Central (versão 2.10.0, de 19/08/2026) descreve devoluções totais ou parciais, sempre ligadas ao Pix original pelo seu End-to-end ID. Na API da xFlow, o recorte é menor: a devolução é total e única por cobrança.
O MED, Mecanismo Especial de Devolução, é outra coisa. Segundo a página Segurança no Pix do Banco Central, consultada em 25/10/2026, ele serve para vítimas de fraude tentarem recuperar valores. Quem aciona é o pagador, pelo app da instituição dele, em até 80 dias após a transação. O MED não se aplica a desacordos comerciais e não garante a devolução.
| Estorno pela API | MED | |
|---|---|---|
| Quem inicia | Você, o recebedor | O pagador, na instituição dele |
| Motivo | Qualquer um: desistência, erro, troca | Suspeita de fraude |
| Como chega até você | Você chama POST /charges/{id}/refund |
Webhook dispute.opened |
| Desfecho | transaction.refunded ou transaction.refund_failed |
dispute.accepted ou dispute.rejected |
Na xFlow, os eventos dispute.* são disparados quando a conta tem MED ativo. A defesa é respondida no painel, em Disputas, dentro do prazo. Pela documentação, contas em plano sem MED não precisam agir, porque a equipe da xFlow cuida dessas contestações.
Conteúdo informativo, atualizado em 25/10/2026. Não substitui orientação jurídica.
Perguntas frequentes
Dá para fazer estorno parcial de Pix pela API?
Não na API da xFlow. O estorno é sempre do valor total da cobrança e pode ser feito uma vez por cobrança. Repetir o pedido devolve o mesmo estorno, sem estornar de novo.
Qual o prazo para estornar um Pix pela API?
Até 90 dias após o pagamento, e só para cobranças com status paid. Depois desse prazo, a API responde 422 refund_window_expired.
Estorno, devolução e MED são a mesma coisa?
Não. Estorno, ou devolução, é você, recebedor, devolvendo o valor ao pagador. O MED é um mecanismo do Pix para vítimas de fraude, acionado pelo pagador na instituição dele, e não se aplica a desacordos comerciais.
O que acontece com o meu saldo durante o estorno?
Enquanto o estorno está pending, o valor líquido fica retido do saldo disponível e não pode ser sacado. Se o PSP recusar, o webhook transaction.refund_failed avisa e o valor retido volta ao saldo.