> For the complete documentation index, see [llms.txt](https://support.swisspay.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://support.swisspay.ai/api-reference/refunds.md).

# Refunds

Refunds return funds from a successful payment back to the customer. SwissPay supports **full** and **partial** refunds, and a single payment can be refunded multiple times up to its captured amount.

## The Refund object

```json
{
  "id": "re_01HABCXYZ...",
  "payment": "pay_01HABCXYZ...",
  "amount": 1000,
  "currency": "CHF",
  "status": "pending",
  "reason": null,
  "metadata": { "order_note": "wrong size" },
  "created_at": "2026-05-20T12:00:00Z"
}
```

| Field        | Type           | Notes                                                          |
| ------------ | -------------- | -------------------------------------------------------------- |
| `id`         | string         | Stable, prefixed with `re_`.                                   |
| `payment`    | string         | The `pay_...` ID being refunded.                               |
| `amount`     | integer        | Minor units.                                                   |
| `currency`   | string         | ISO 4217. Always matches the original payment.                 |
| `status`     | string         | The refund's current state. See *Refund lifecycle* below.      |
| `reason`     | string \| null | Optional free-text reason you supplied on creation.            |
| `metadata`   | object         | Up to 50 string keys, values ≤ 500 bytes. Echoed back on read. |
| `created_at` | string         | ISO 8601 UTC.                                                  |

***

## Create a refund

```
POST /api/v1/payments/{payment_id}/refunds
```

### Required headers

```
Authorization: Bearer sk_test_...
Content-Type: application/json
Idempotency-Key: <unique-per-attempt>
```

`Idempotency-Key` is required — refunds move money and must be safe to retry. See [Idempotency](/api-reference/idempotency.md).

### Body fields

All fields are optional. An empty body refunds the full remaining refundable amount of the payment.

| Field      | Type    | Notes                                                                                     |
| ---------- | ------- | ----------------------------------------------------------------------------------------- |
| `amount`   | integer | Minor units. Must be ≤ the payment's remaining refundable amount. Omit for a full refund. |
| `reason`   | string  | Free-text reason. Stored on the refund and returned on read.                              |
| `metadata` | object  | Up to 50 keys, values ≤ 500 bytes. Stored verbatim and echoed back on read.               |

### Example — full refund

```bash
curl -X POST https://app.swisspay.ai/api/v1/payments/pay_01HABCXYZ/refunds \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'
```

### Example — partial refund with metadata

```json
{
  "amount": 1000,
  "reason": "Item returned",
  "metadata": { "order_note": "wrong size" }
}
```

### Multiple partial refunds

A payment can be refunded more than once as long as the sum of refund amounts does not exceed the captured amount. Each call returns its own Refund object with its own `id`.

### Refund lifecycle

A refund is created in `pending` while SwissPay forwards the request to the upstream processor. Once the processor confirms, the refund transitions to a terminal state. The refund's `id` is stable across the transition — poll `GET /api/v1/refunds/{id}` (or list refunds on the payment) to observe the final state.

***

## Retrieve a refund

```
GET /api/v1/refunds/{id}
```

```bash
curl https://app.swisspay.ai/api/v1/refunds/re_01HABCXYZ \
  -H "Authorization: Bearer sk_test_..."
```

Unknown IDs — including IDs that belong to another merchant — return `404 Not Found` with no body.

***

## List refunds for a payment

```
GET /api/v1/payments/{payment_id}/refunds?page=1&per_page=20
```

| Query param | Default | Max   |
| ----------- | ------- | ----- |
| `page`      | `1`     | —     |
| `per_page`  | `20`    | `100` |

```bash
curl 'https://app.swisspay.ai/api/v1/payments/pay_01HABCXYZ/refunds' \
  -H "Authorization: Bearer sk_test_..."
```

Response:

```json
{
  "data": [ /* refund objects */ ],
  "page": 1,
  "per_page": 20,
  "total_count": 2,
  "has_more": false
}
```

***

## See also

* [Payments](/api-reference/payments.md) — the resource refunds operate on.
* [Idempotency](/api-reference/idempotency.md) — pick the right `Idempotency-Key`.
* [Errors](/api-reference/errors.md) — every error code we return.
