SelectwinDOCS
Transações

Reembolsar uma transação

Devolve ao cliente o valor de uma transação já aprovada, total ou parcialmente, respeitando os prazos e limites do meio de pagamento. Use quando precisar estornar uma compra — por desistência, produto

Devolve ao cliente o valor de uma transação já aprovada, total ou parcialmente, respeitando os prazos e limites do meio de pagamento. Use quando precisar estornar uma compra — por desistência, produto indisponível, cobrança incorreta ou acordo comercial.

POST /v1/transactions/{transactionId}/refund

Como funciona

Um reembolso (em inglês, refund) é a operação que devolve dinheiro ao cliente de uma transação que já foi paga (status approved). É diferente de cancelar uma transação ainda não capturada: aqui o valor já saiu do cliente e entrou no seu saldo, então o reembolso debita o seu saldo para devolver ao portador.

Quando você chama este endpoint, o servidor:

  1. Valida que o transactionId existe e está em estado elegível (approved).
  2. Registra o reembolso, gera um comprovante (receipt com type: "refund") e dispara o estorno no adquirente / meio de pagamento.
  3. Atualiza a transação para status: "refunded" e marca os recebíveis afetados como refunded (preenchendo refundedAt).
  4. Devolve a transação completa, já com o novo reembolso dentro do array refunds[].

A devolução ao cliente não é instantânea: o adquirente processa o estorno em segundo plano. Em cartão de crédito, o valor pode levar de 1 a 2 faturas para aparecer; em PIX/boleto, o fluxo de devolução é diferente e pode exigir dados bancários do cliente. A resposta 200 confirma que o reembolso foi aceito e registrado, não que o dinheiro já chegou ao cliente.

Importante

O reembolso é irreversível. Uma vez que a transação entra em refunded, não há operação para "desfazer" o estorno — seria necessário uma nova cobrança. Confirme o valor e o motivo antes de enviar.

Acompanhe pelo webhook, não por polling

Como o estorno é assíncrono, não fique consultando a transação em laço para saber se o reembolso concluiu. Assine os eventos de webhook da transação (ex.: transaction.refunded) e reaja à notificação. Veja Proibição de polling e Webhook Events.

Quando usar (e quando não usar)

Use o reembolso para:

  • Desistência da compra após o pagamento ter sido aprovado.
  • Produto indisponível / esgotado depois de confirmado o pedido.
  • Produto defeituoso devolvido pelo cliente.
  • Cobrança incorreta — estorno de valor cobrado a mais.
  • Acordo comercial ou resolução amigável de uma reclamação.

Quando não usar:

SituaçãoOperação correta
Transação ainda pré-autorizada (não capturada)Não capture — veja Capture. Sem captura, não há dinheiro a devolver.
Cliente abriu contestação no banco (chargeback)Trate pela Dispute; reembolsar por fora pode gerar devolução em dobro.
Quer apenas consultar o estadoUse Read ou List.

Atenção

Se já existe uma disputa em andamento para a transação, o reembolso pode ser bloqueado com transactionDisputeInProcess. Resolva a disputa primeiro — reembolsar e perder o chargeback ao mesmo tempo significa pagar duas vezes.

Requisição

Headers

CabeçalhoObrigatórioDescrição
SelectKeySimSua chave de API. Em produção começa com sl_live_; em sandbox, sl_test_. Veja Autenticação.
Content-Type: application/jsonSim (com corpo)Indica que o corpo é JSON.
X-Idempotency-KeyRecomendadoGarante que repetir a mesma chamada não gere dois reembolsos. Veja Idempotência.

Dica

Reembolso é uma operação de escrita que mexe em dinheiro: sempre envie um X-Idempotency-Key. Se a rede cair depois de o servidor já ter processado, repetir com a mesma chave devolve o mesmo resultado em vez de estornar de novo.

Parâmetros de caminho

ParâmetroTipoObrigatórioDescrição
transactionIdstringSimID da transação a reembolsar, com prefixo tra_ (ex.: tra_01hqzvabc). Trate como opaco — veja Convenções.

Corpo da requisição

CampoTipoObrigatórioDescrição
reasonstringNãoMotivo do reembolso, registrado para auditoria. Recomendado por boa prática, mesmo sendo opcional.

O corpo é opcional: para um reembolso total, você pode enviar {} ou nem incluir corpo. Inclua reason para deixar rastro do porquê do estorno.

Exemplo curl

curl -X POST https://api.selectwin.io/v1/transactions/tra_01hqzvabc/refund \
  -H "SelectKey: sl_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: refund-pedido-1042-001" \
  -d '{
    "reason": "Cliente desistiu da compra e solicitou reembolso"
  }'

Resposta

200 OK — o reembolso foi aceito e registrado. O corpo é a transação completa já atualizada para status: "refunded", acompanhada de um receipt (comprovante de reembolso) e do novo item em refunds[].

{
  "receipt": {
    "id": "rpt_01hqzvabc",
    "type": "refund",
    "amount": 5000,
    "description": "Comprovante de reembolso",
    "merchant": {
      "id": "bus_1234567890",
      "name": "Seller Name",
      "statement": "SELLERNAME",
      "document": "12345678000190",
      "documentType": "cnpj",
      "naturalness": "pt-BR"
    },
    "payment": {
      "id": "tra_01hqzvabc",
      "customId": "PEDIDO-1042",
      "externalId": "order-9981",
      "status": "refunded",
      "amount": 5000,
      "currency": "BRL",
      "method": "credit",
      "card": {
        "brand": "visa",
        "holder": "JOAO SILVA",
        "first4Digits": "411111",
        "last4Digits": "1111"
      },
      "installments": 3,
      "transactionNumber": "A1B2C3D4E5",
      "approvedAt": "2026-04-12T17:56:33.000Z",
      "refundedAt": "2026-04-13T10:00:00.000Z",
      "canceledAt": null,
      "reversedAt": null,
      "chargedbackAt": null
    },
    "customer": {
      "id": "cus_01hqzvabc",
      "firstName": "João",
      "lastName": "Silva",
      "email": "[email protected]",
      "document": "12345678901",
      "documentType": "cpf",
      "telephone": "5511999999999"
    },
    "updatedAt": "2026-04-13T10:00:00.000Z",
    "createdAt": "2026-04-13T10:00:00.000Z"
  },
  "id": "tra_01hqzvabc",
  "customId": "PEDIDO-1042",
  "amount": 5000,
  "originalAmount": 5000,
  "status": "refunded",
  "method": "credit",
  "currency": "BRL",
  "payment": {
    "provider": "selectwin",
    "version": "1.1",
    "acquirerTransactionNumber": "A1B2C3D4E5",
    "cardFirstDigits": "411111",
    "cardLastDigits": "1111",
    "cardBrand": "visa",
    "installments": 3,
    "paidAt": "2026-04-12T17:56:33.000Z",
    "invoiceLink": "https://selectwin.io/invoices/tra_01hqzvabc"
  },
  "discount": null,
  "customer": {
    "id": "cus_01hqzvabc",
    "firstName": "João",
    "lastName": "Silva",
    "email": "[email protected]"
  }
}

Campos-chave da resposta

CampoTipoDescrição
statusstringPassa a refunded quando a transação é estornada.
receiptobjectComprovante gerado para esta operação.
receipt.typestringVale refund neste endpoint — identifica o comprovante como de reembolso.
receipt.amountintegerValor reembolsado, em centavos (5000 = R$ 50,00).
receipt.payment.statusstringStatus do pagamento dentro do comprovante (refunded).
receipt.payment.refundedAtstring (ISO 8601 UTC)Momento em que o reembolso foi registrado.
amount / originalAmountintegerValor atual e valor original da transação, em centavos.

A transação completa traz muitos outros campos (payment, customer, billing, receivables, splits, refunds, timeline, _links, …) — os mesmos descritos em Read. Acima mostramos o recorte essencial para o reembolso. Valores monetários sempre em centavos e datas em ISO 8601 UTC, conforme Convenções.

Erros

A API sinaliza falhas pelo envelope de erro padrão. Trate sempre pelo error.code, não pela mensagem — veja Tratamento de Erros e o Catálogo de Códigos de Erro.

error.codeHTTPQuando ocorre
transactionIdIsInvalid400O transactionId é malformado ou não corresponde a uma transação válida.
invalidParameters400Falha de validação no corpo (ex.: reason excede o tamanho permitido). Veja error.params.
unauthorized401SelectKey ausente, inválida ou revogada.
insufficientFundsError402Saldo insuficiente para cobrir o reembolso no momento da operação.
forbidden403Autenticado, mas sem permissão para reembolsar (ou limite atingido).
transactionNotFound404Não existe transação com esse ID.
transactionRefundNotProcessable409A transação não está em estado que permita reembolso (ex.: não está approved, já reembolsada).
transactionDisputeInProcess409Há uma disputa em andamento — resolva-a antes de reembolsar.
unprocessableEntity422A regra de negócio impede processar o reembolso.
tooManyRequests429Limite de requisições excedido. Respeite error.retryAfterMinutes e use backoff.
serverError500Erro interno. Repita com backoff; se persistir, contate o suporte.

Exemplo de erro quando a transação não está em estado reembolsável:

{
  "error": {
    "code": "transactionRefundNotProcessable",
    "statusCode": 409,
    "category": "client",
    "message": "Transaction refund not processable"
  }
}

Boas práticas

  1. Sempre envie X-Idempotency-Key. Reembolso mexe em dinheiro; a chave evita estornos duplicados se a requisição for reenviada após timeout de rede.
  2. Confirme o status antes de reembolsar. Faça um Read e verifique status: "approved" para falhar cedo e com mensagem clara, em vez de tomar um transactionRefundNotProcessable.
  3. Preencha reason sempre. Embora opcional, o motivo vira trilha de auditoria e ajuda a conciliar estornos depois.
  4. Reaja por webhook, não por polling. Use os eventos da transação para saber quando o estorno concluiu de fato; veja Proibição de polling.
  5. Verifique disputas antes. Se há transactionDisputeInProcess, conduza a Dispute primeiro para não pagar em dobro.
  6. Comunique o prazo ao cliente. Em cartão de crédito, o valor pode levar 1 a 2 faturas para aparecer; em PIX/boleto, pode ser necessário coletar dados bancários para a devolução.
  7. Considere o impacto no saldo. O valor reembolsado debita seu saldo na hora — para estornos de alto valor, garanta saldo disponível para evitar insufficientFundsError.

Veja também

How is this guide?

On this page