> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chargefy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Reembolsos

> Devolva parte ou todo o valor capturado em uma charge e acompanhe a liquidação.

Um **reembolso** (`refund`) devolve dinheiro que já foi capturado em uma [charge](/features/charges): ele reverte parte ou todo o valor cobrado e aponta sempre para a charge de origem. É o objeto que responde "essa cobrança foi devolvida, deu certo, e quanto voltou?".

<Info>
  **Refund ≠ cancelamento**

  Cancelar interrompe uma cobrança que **ainda não capturou** dinheiro (um `payment_intent` ou uma `charge` em andamento). Um **refund** atua sobre valor que **já entrou**: ele devolve o que foi capturado. Por isso o refund só existe para uma charge `succeeded`, paga e capturada.
</Info>

## Modelo conceitual

Cada refund nasce de uma charge e carrega de volta as referências que aquela charge tinha: o `payment_intent` que a originou e, quando existem, a `invoice`, o `customer` e o `payment_method`.

```mermaid theme={}
flowchart LR
  PI[Payment Intent] -- confirma --> C[Charge capturada]
  C -- POST /v1/refunds --> R1[Refund parcial]
  C --> R2[Refund parcial]
  R1 -.-> CU[Customer]
  R1 -.-> IN[Invoice]
  R1 -.-> PI
```

| Objeto                        | Papel                                           | Quem cria                         |
| ----------------------------- | ----------------------------------------------- | --------------------------------- |
| [`charge`](/features/charges) | A cobrança capturada que será revertida.        | O sistema, ao confirmar o intent. |
| `refund`                      | A devolução de parte ou todo o valor da charge. | Você (`POST /v1/refunds`).        |

Uma mesma charge pode ter **vários refunds parciais**. O valor disponível para reembolsar é o valor capturado menos os refunds já `pending`, `requires_action` ou `succeeded`.

## Anatomia do refund

| Campo            | Tipo             | Descrição                                                                        |
| ---------------- | ---------------- | -------------------------------------------------------------------------------- |
| `amount`         | `integer`        | Valor reembolsado, **em centavos**.                                              |
| `charge`         | `string`         | Charge de origem (`ch_*`). Sempre presente.                                      |
| `currency`       | `string`         | Moeda em 3 letras minúsculas (`brl`).                                            |
| `customer`       | `string \| null` | Customer relacionado (`cus_*`).                                                  |
| `failure_reason` | `string \| null` | Motivo normalizado da falha quando `status = failed`; `null` nos demais estados. |
| `invoice`        | `string \| null` | Invoice relacionada (`inv_*`).                                                   |
| `payment_intent` | `string \| null` | Intent que originou a charge (`pi_*`).                                           |
| `payment_method` | `string \| null` | Método usado na charge (`pm_*`).                                                 |
| `reason`         | `string \| null` | Motivo informado na criação; `null` quando não foi enviado.                      |
| `status`         | `string`         | `pending`, `requires_action`, `succeeded`, `failed` ou `canceled`.               |
| `metadata`       | `object`         | Pares chave→valor livres, controlados por você. `{}` quando vazio.               |

O schema público completo, com cada campo retornado, está em [Objeto refund](/api-reference/refunds).

### Exemplo reduzido

```json theme={}
{
  "id": "re_123",
  "object": "refund",
  "amount": 5000,
  "charge": "ch_456",
  "currency": "brl",
  "payment_intent": "pi_789",
  "reason": "requested_by_customer",
  "status": "succeeded"
}
```

## Criar um refund

Refund é uma ação que **materializa um recurso próprio**: você o cria com `POST /v1/refunds` apontando para uma `charge` capturada ou para um `payment_intent` que já tenha uma charge reembolsável. Sem `amount`, o refund usa **todo o valor ainda disponível** da charge resolvida.

| Campo            | Tipo      | Regra                                                                                     |
| ---------------- | --------- | ----------------------------------------------------------------------------------------- |
| `charge`         | `string`  | Charge a reembolsar (`ch_*`). Envie `charge` ou `payment_intent`, não ambos.              |
| `payment_intent` | `string`  | Payment Intent a reembolsar (`pi_*`). A Chargefy resolve internamente a charge capturada. |
| `amount`         | `integer` | Valor em centavos, inteiro `> 0`. Omitido = valor disponível inteiro (refund total).      |
| `reason`         | `string`  | Motivo público do refund: `duplicate`, `fraudulent` ou `requested_by_customer`.           |
| `metadata`       | `object`  | Pares chave→valor livres para correlacionar com o seu sistema.                            |

<CodeGroup>
  ```bash Refund total theme={}
  curl -X POST https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "charge": "ch_456"
    }'
  ```

  ```bash Refund parcial com motivo theme={}
  curl -X POST https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 5000,
      "charge": "ch_456",
      "reason": "requested_by_customer"
    }'
  ```

  ```bash Refund por payment_intent theme={}
  curl -X POST https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 5000,
      "payment_intent": "pi_789",
      "reason": "requested_by_customer"
    }'
  ```

  ```bash Com idempotência e metadata theme={}
  curl -X POST https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: refund-order-1001" \
    -d '{
      "amount": 5000,
      "charge": "ch_456",
      "metadata": { "order_id": "1001" },
      "reason": "duplicate"
    }'
  ```
</CodeGroup>

<Tip>
  Use o header `Idempotency-Key` (ou `idempotency_key` no body) para criar o refund com segurança em caso de retry. Repetir a mesma chave devolve o refund já criado em vez de gerar uma cobrança em duplicidade.
</Tip>

<Note>
  Chargeback/dispute não é `reason` de refund. Use `fraudulent` quando você estiver fazendo uma devolução voluntária por fraude; disputa de cartão é outro fluxo financeiro.
</Note>

### Quando uma charge é reembolsável

O refund só prossegue se a charge estiver de fato capturada. A charge precisa estar `succeeded`, paga, capturada e com valor capturado `> 0`. Fora disso, a criação falha:

| Situação                                                | HTTP  | `message`                                  |
| ------------------------------------------------------- | ----- | ------------------------------------------ |
| Charge não encontrada na organização                    | `404` | No such charge.                            |
| Charge não está capturada/paga                          | `409` | Charge is not refundable.                  |
| Charge sem valor disponível (já totalmente reembolsada) | `409` | Charge has no refundable amount remaining. |
| `amount` maior que o valor disponível                   | `400` | Refund amount exceeds refundable amount.   |
| `amount` não inteiro ou `≤ 0`                           | `400` | amount must be a positive integer.         |
| Charge não pode ser reembolsada automaticamente         | `422` | Charge cannot be refunded automatically.   |

Quando o `payment_intent` ainda está em `requires_capture`, ele não tem valor capturado para refund. Cancele o intent com `POST /v1/payment-intents/{id}/cancel` em vez de criar um refund.

<Warning>
  Reembolso é **irreversível**. Não há endpoint para "desfazer" um refund: uma vez que ele liquida, o dinheiro voltou. Para devolver mais valor da mesma charge, crie um **novo** refund parcial enquanto houver valor disponível.
</Warning>

## Ciclo de vida e liquidação

A criação devolve o refund já com o estado retornado pela liquidação — que pode ser imediato ou assíncrono, dependendo do meio. Quando ainda não há confirmação final, o refund nasce `pending` ou `requires_action` e migra de estado depois, comunicado por webhook.

```mermaid theme={}
stateDiagram-v2
  [*] --> pending: POST /v1/refunds
  [*] --> requires_action: precisa de ação
  requires_action --> pending: ação concluída
  pending --> succeeded: valor devolvido
  pending --> failed: não foi possível devolver
  pending --> canceled: reversão cancelada
```

| Status            | Significado                                                   |
| ----------------- | ------------------------------------------------------------- |
| `pending`         | Refund registrado, aguardando a confirmação da devolução.     |
| `requires_action` | Refund aguardando ação para continuar.                        |
| `succeeded`       | Valor devolvido com sucesso.                                  |
| `failed`          | Não foi possível concluir a devolução. Veja `failure_reason`. |
| `canceled`        | A reversão foi cancelada antes de concluir.                   |

<Note>
  Como a liquidação pode ser assíncrona, **não faça polling**: trate o `status` retornado na criação como provisório e reaja aos webhooks `refund.created`, `refund.updated` e `refund.failed` para acompanhar a transição até `succeeded`, `failed` ou `canceled`.
</Note>

## Consultar e listar

Refund é recurso financeiro auditável: você cria, consulta, lista e atualiza apenas a `metadata`.

| Operação            | Verbo  | URL                |
| ------------------- | ------ | ------------------ |
| Criar refund        | `POST` | `/v1/refunds`      |
| Consultar um refund | `GET`  | `/v1/refunds/{id}` |
| Listar refunds      | `GET`  | `/v1/refunds`      |
| Atualizar metadata  | `POST` | `/v1/refunds/{id}` |

A listagem é por **cursor** (`starting_after`, `ending_before`, `limit` de `1` a `100`), em ordem decrescente de criação. Filtros disponíveis:

| Filtro                                                       | Casa com                                                           |
| ------------------------------------------------------------ | ------------------------------------------------------------------ |
| `charge`                                                     | Refunds de uma charge (`ch_*`).                                    |
| `customer`                                                   | Refunds de um customer (`cus_*`).                                  |
| `invoice`                                                    | Refunds de uma invoice (`inv_*`).                                  |
| `payment_intent`                                             | Refunds de um intent (`pi_*`).                                     |
| `status`                                                     | `pending`, `requires_action`, `succeeded`, `failed` ou `canceled`. |
| `created[gte]`, `created[gt]`, `created[lte]`, `created[lt]` | Data de criação por ISO-8601 ou Unix seconds.                      |

<CodeGroup>
  ```bash Refunds de uma charge theme={}
  curl -G https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -d charge=ch_456 \
    -d limit=10
  ```

  ```bash Só os concluídos de um cliente theme={}
  curl -G https://api.chargefy.io/v1/refunds \
    -H "Authorization: Bearer {{API_KEY}}" \
    -d customer=cus_123 \
    -d status=succeeded
  ```

  ```bash Consultar um refund theme={}
  curl https://api.chargefy.io/v1/refunds/re_123 \
    -H "Authorization: Bearer {{API_KEY}}"
  ```
</CodeGroup>

## Webhooks

Mudanças no refund disparam eventos cujo `data.object` carrega o objeto `refund` completo, no mesmo shape do `GET /v1/refunds/{id}`.

| Evento            | Quando dispara                                              |
| ----------------- | ----------------------------------------------------------- |
| `refund.created`  | O refund foi criado.                                        |
| `refund.failed`   | O refund chegou ao estado `failed`.                         |
| `refund.updated`  | Algum campo público do refund mudou (tipicamente `status`). |
| `charge.refunded` | A charge recebeu um refund parcial ou total.                |

O evento `refund.updated` também traz `data.previous_attributes` com os valores anteriores dos campos alterados — por exemplo, `status` saindo de `pending` para `succeeded`.

<Warning>
  Reaja aos webhooks em vez de fazer polling. Ao receber `refund.created`, `refund.updated` ou `refund.failed`, consulte o refund pelo `id` do payload para conciliar com o seu pedido — `metadata` é o caminho para correlacionar com o seu sistema.
</Warning>

## Próximos passos

<CardGroup cols={2}>
  <Card title="Objeto refund" icon="rotate-left" href="/api-reference/refunds">
    Schema público completo e cada campo retornado.
  </Card>

  <Card title="Criar refund (API)" icon="code" href="/api-reference/refunds/create">
    Contrato do `POST /v1/refunds`, com `amount`, `reason` e idempotência.
  </Card>

  <Card title="Charges" icon="receipt" href="/features/charges">
    A cobrança capturada que um refund reverte.
  </Card>

  <Card title="Payment Intents" icon="bullseye" href="/features/payment-intents">
    O processo que materializa a charge a ser reembolsada.
  </Card>
</CardGroup>
