# Refunds

Refund a full or partial charge — from the dashboard or with the API.

# Refunds

Refunds can be issued through the **Dashboard → Transactions → Refund** action or with the public API.

## Endpoints

| Method | Path | Scope | Purpose |
|---|---|---|---|
| `POST` | `/v1/refunds` | `refunds:write` | Issue a full or partial refund. |
| `GET` | `/v1/refunds?charge=ch_…` | `refunds:read` | List refunds for one charge (`payment_intent=` also accepted). |
| `GET` | `/v1/refunds/{id}` | `refunds:read` | Retrieve a single refund. |

Listing requires a `charge` or `payment_intent` filter — refunds are always scoped to a charge that belongs to your account.

## How it works

1. Merchant clicks **Refund** on a `succeeded` transaction and enters an amount (full or partial).
2. Southbill issues a reversal of the destination transfer on the platform account so the money comes out of the merchant's balance, not Southbill's.
3. Southbill also reverses the pro-rata **application fee** — you only keep fees for what the buyer actually paid.
4. Transaction status becomes `refunded` (full) or `partially_refunded` (partial).
5. A `checkout.session.refunded` webhook fires.

## Rules

- You cannot refund a `disputed` charge — resolve the dispute first. The API returns `422 invalid_state` with code `charge_disputed`.
- Refunds can be issued for **up to 180 days** after the original charge (processor limit).
- Partial refunds can be issued multiple times up to the total captured amount.
- Fee reversal is automatic and visible in the merchant's **Wallet** as `Southbill fee refund`.

## Webhook payload (`checkout.session.refunded`)

```json
{
  "type": "checkout.session.refunded",
  "data": {
    "object": {
      "charge_id": "ch_…",
      "session_id": "cs_…",
      "amount_refunded": 1990,
      "amount": 4990,
      "currency": "EUR",
      "reason": "requested_by_customer",
      "fully_refunded": false
    }
  }
}
```

