# 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://staging.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://staging.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://staging.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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://support.swisspay.ai/api-reference/refunds.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
