> For the complete documentation index, see [llms.txt](https://docs.loomgate.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.loomgate.io/en/concepts/refunds.md).

# Refunds

How much you can refund, refund fees, statuses and how to call the API safely.

You refund the buyer of a `succeeded` payment from the dashboard (the payment detail page) or with `POST /partner/v1/refunds`. You can refund several times, part of the amount each time.

## How much you can refund

{% hint style="info" %}
**Fees are never refunded**, neither to the buyer nor to you.
{% endhint %}

Each payment has `amount_refundable`, the amount that can still be refunded:

```
amount_refundable = amount_total − processing_fee − bank_fee − amount_refunded
```

`amount_refundable` is 0 while the payment has not `succeeded`.

|                               | Buyer pays the fees | You pay the fees |
| ----------------------------- | ------------------- | ---------------- |
| `amount`                      | 10000               | 10000            |
| `amount_total`                | 10320               | 10000            |
| `processing_fee` + `bank_fee` | 290 + 30            | 290 + 30         |
| Initial `amount_refundable`   | **10000**           | **9680**         |

* Buyer pays the fees: the buyer gets back at most `amount`; the fee line they paid is not refunded.
* You pay the fees: you can refund at most what you received. To give the buyer everything back, send them the difference yourself outside Loomgate.

Omit `amount` to refund all of `amount_refundable`. Going over returns `refund_exceeds_remaining`; a payment that has not succeeded returns `payment_not_refundable`.

## Refund fee

Each refund may carry a `refund_fee` according to your fee schedule. This fee is charged to you, comes **on top of** the refunded amount (the buyer still receives the full `amount` of the refund) and is deducted from your balance.

## Statuses

| Status                  | Meaning                                                                                                   |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| `pending`, `processing` | In progress. The amount is already reserved: the payment's `amount_refunded` includes refunds in progress |
| `succeeded`             | Refunded. Webhook `refund.succeeded`                                                                      |
| `failed`                | Could not be refunded; the reserved amount is released back to the payment. Webhook `refund.failed`       |

## Call safely with `Idempotency-Key`

Send an `Idempotency-Key` header so that you can retry without ever refunding twice:

* Generate **one key per refund** (for example `refund-1042-1`), store it before the call, and reuse that exact key on every retry after a timeout, network error, 429 or 5xx.
* Same key, same body: you get back the original refund (same `id`, current status), even when two requests run at the same time.
* Same key, different body: `409 idempotency_key_reused`. To refund another part, use a new key.
* A request that ends in an error stores nothing: sending the same key again runs it from scratch.
* No key and a timeout: re-read the payment's `amount_refunded` before calling again, otherwise you may refund twice.

Keys are shared between creating payments and refunds (including refunds made in the dashboard), so use different prefixes for the two.

## Effect on your balance

While the payment still has locked unlock steps, the refund and then its refund fee are taken from that payment's locked steps, the nearest unlock time first, then the next ones (the step's `deducted` grows and its `remaining` shrinks); what no locked step holds is deducted from your available balance at once. Once every step is unlocked, a refund is deducted from your available balance at once. See [Balance and unlock times](/en/concepts/balance.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.loomgate.io/en/concepts/refunds.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
