# Refund an order

Credit money back on a captured order with POST /refunds, in full or in part, with return fees where the market supports them and allocated to the right shipment.

Refunding returns money you have already captured. It's a separate call from cancelling,
which releases money you never took — if any part of the order is captured, refund is the
only way back. This page covers refunding in full and refunding in part. You need a captured
order and a credential for its environment.

## Before you start

Paths are relative to your [base URL](/api/authentication/#base-urls):
`https://api.playground.kustom.co/` while testing, `https://api.kustom.co/` in production.

**Send a `Kustom-Idempotency-Key` on every write.** Every `POST` and `PATCH` to Order Management moves money or changes the order. Send a `Kustom-Idempotency-Key` header with one UUID per operation, and reuse it when you retry, so a call repeated after a timeout runs once instead of twice. [Idempotency and retries](/order-management/idempotency-and-retries/) has the rules and the retry schedule.

Read the order first. `refunded_amount` may not exceed `captured_amount`, and that's the
constraint most refused refunds hit.

## Refund

Refund everything you captured when the whole order comes back.

```http
POST /ordermanagement/v1/orders/{order_id}/refunds
Kustom-Idempotency-Key: 4c2e8a51-7d3f-4b6e-9a10-5f8d2c7e1b94
Content-Type: application/json
```

```json
{
  "refunded_amount": 20000,
  "reference": "4c2e8a51-7d3f-4b6e-9a10-5f8d2c7e1b94",
  "description": "Returned: the whole order"
}
```

`refunded_amount` is the only required field. `description` is shown to the customer, so
write it for them rather than for your logs.

A successful refund returns `201 Created` with an empty body and the new refund's id in two
headers, `Refund-Id` and `Location`. Use that `Location` as returned rather than assembling
one. Then re-read the order: `refunded_amount` should have risen by what you refunded.

## Partial refund

Refund part of what you captured — a returned item, say — with a smaller `refunded_amount`,
and send the order lines being returned. The lines are optional in general but are what
drives allocation when the order shipped in parts.

```http
POST /ordermanagement/v1/orders/{order_id}/refunds
Kustom-Idempotency-Key: 9dfcd4b6-9428-4835-ad93-3720ea808608
Content-Type: application/json
```

```json
{
  "refunded_amount": 10000,
  "reference": "9dfcd4b6-9428-4835-ad93-3720ea808608",
  "description": "Returned: one pair of sneakers",
  "order_lines": [
    {
      "type": "physical",
      "reference": "B24680",
      "name": "Sneakers",
      "quantity": 1,
      "quantity_unit": "pcs",
      "unit_price": 10000,
      "total_amount": 10000,
      "tax_rate": 2500,
      "total_tax_amount": 2000
    }
  ]
}
```

### Deducting a return fee

Supported in Austria, Germany, Denmark, Finland, France, the Netherlands, Norway and Sweden,
and only on an order that was fully captured in a single capture. Model the fee as an order
line of type `return_fee` with a negative amount, and make the lines sum to
`refunded_amount`:

```json
{
  "refunded_amount": 9500,
  "reference": "1786c73b-a2be-4d42-a9f7-ff1c4bca5ccc",
  "description": "Returned: one T-shirt, less return postage",
  "order_lines": [
    { "type": "physical",   "name": "T-Shirt",    "quantity": 1, "unit_price": 10000, "total_amount": 10000 },
    { "type": "return_fee", "name": "Return fee", "quantity": 1, "unit_price": -500,  "total_amount": -500 }
  ]
}
```

### When the order shipped in parts

Send order lines whose `reference` values are the same ones you sent on the capture that
contained the returned goods. Kustom uses those references to allocate the credit to the
right invoice.

Say an order shipped as two captures:

```json
{
  "captured_amount": 10000,
  "description": "Capture A — T-shirt and jeans",
  "order_lines": [
    { "type": "physical", "reference": "A12345", "name": "T-shirt", "quantity": 1, "unit_price": 3000, "total_amount": 3000 },
    { "type": "physical", "reference": "A98765", "name": "Jeans",   "quantity": 1, "unit_price": 7000, "total_amount": 7000 }
  ]
}
```

```json
{
  "captured_amount": 10000,
  "description": "Capture B — sneakers",
  "order_lines": [
    { "type": "physical", "reference": "B24680", "name": "Sneakers", "quantity": 1, "unit_price": 10000, "total_amount": 10000 }
  ]
}
```

The customer returns the sneakers, so the refund must carry `B24680` — the reference from
**Capture B**, the capture the sneakers were in. That's the refund body above. Sending
`A12345` instead, or sending no lines at all, credits the wrong invoice.

The lines must sum exactly to `refunded_amount`, and `refunded_amount` must be no greater
than the `captured_amount` of the capture being refunded. Check in the Kustom Portal that the
credit landed on the invoice you expected: the API call succeeds either way.

## Release what you never captured

If you're not going to capture the rest of an order, release the remaining authorization
rather than leaving it to expire:

```http
POST /ordermanagement/v1/orders/{order_id}/release-remaining-authorization
Kustom-Idempotency-Key: 2471e418-d208-49b4-bce4-d2cd45dbc1d4
```

No body. Returns `204 No Content`. This isn't a refund — nothing captured moves — it just
frees the reservation on the customer's side.

## Troubleshooting

Errors carry `error_code`, `error_messages` and a `correlation_id`. Branch on the code,
and quote the correlation id to support.

The one to recognize is
[`REFUND_NOT_ALLOWED`](/api/errors/#error-order-management-refund-not-allowed): the order
doesn't have that much captured amount left to return — nothing has been captured yet, the
captured amount is already fully refunded, or `refunded_amount` is larger than what remains. It describes the order's state, not your request,
so retrying the same call can't succeed — capture first, or check `captured_amount` against
what you've already returned.

## Related

- [Settlements](/finance/) — how refunds show up in what you're paid
- [Capture an order](/order-management/capture/) — the references allocation depends on
- [Update or cancel an order](/order-management/update-and-cancel/) — cancelling instead, when nothing is captured
- [Order Management](/order-management/) — where refunds sit in the lifecycle
