---
id: refund
title: "Refund order"
sidebar_label: Refund order
hide_title: true
description: "Management API - Orders - Refund order"
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import Ingress from "../../../src/components/ingress/ingress.react";
import Idempotency from "../idempotency.mdx";

<Ingress title="Refund order">
  If an end customer requires money back as compensation or after returning an
  item. Use this endpoint to refund the entire order, part refund individual
  items, a specific quantity of items of an order or as an adjustment amount.
</Ingress>

:::note Works on `Activated` and `PartActivated` orders
You can only refund what has been captured. See
[Order lifecycle](/docs/manage/concepts/order-lifecycle) for what each status allows.
:::

## Examples

### Full refund

You can refund the entire order by specifying the amount to refund. This only allows for the full amount left on the order that has been captured.
If you are doing a part refund, you will have to provide [items in the request](/docs/manage/orders/models/refund-item) that partial refund can be matched against.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 285.0,
  "description": "Refund description",
  "actionReference": "test-refundref-123"
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Part refund with articles

You can refund part of the order by providing order items, specifying quantity to refund.

:::note Items are matched on a best effort basis
The more data you send, the more likely it is that Walley finds a unique article. If no unique
match can be made, the request fails. Always send `unitPrice` and `quantity`.
:::

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 285.0,
  "actionReference": "test-refundref-123",
  "items": [
    {
      "id": "10001",
      "description": "Shoes",
      "unitPrice": 95,
      "quantity": 1,
      "type": "purchase"
    },
    {
      "id": "10002",
      "description": "T-Shirt",
      "unitPrice": 95,
      "quantity": 2,
      "type": "purchase"
    }
  ]
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Adding fees

Additional fees can be added when refunding (e.g. If you would like to add a return-fee or similar).

- Added fees needs to have the **vat** property set, otherwise it will default to 0.
- When adding fees, the amount set should be the total of items + fees.
- It is not possible to increase the total order value with fees.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 75,
  "actionReference": "test-refundref-123",
  "items": [
    {
      "id": "10001",
      "description": "Shoes",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25,
      "type": "purchase"
    },
    {
      "id": "10002",
      "description": "Return fee",
      "unitPrice": -25,
      "quantity": 1,
      "vat": 25,
      "type": "fee"
    }
  ]
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Adding discounts

Discounts can be added to a refund request to give back money at the same time as refunding.

- Added discounts needs to have the **vat** property set, otherwise it will default to 0.
- Discounts should be added with a positive unit price.
- It is not possible to decrease the total order value with discounts below 0.
- When adding discounts, the amount set should be the total of items + discounts.
- Discounts can be combined with fees.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 150,
  "actionReference": "test-refundref-123",
  "items": [
    {
      "id": "10001",
      "description": "Shoes",
      "unitPrice": 100,
      "quantity": 1,
      "type": "purchase"
    },
    {
      "id": "32455",
      "description": "Discount-50-sale",
      "unitPrice": 50,
      "quantity": 1,
      "vat": 25,
      "type": "discount"
    }
  ]
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Removing fees

Fees can be removed when refunding.

When removing fees, the fee should be **provided with a positive unit price**.
The removed fee should also be added into the total refunded amount.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 125,
  "actionReference": "test-refundref-123",
  "items": [
    {
      "id": "10001",
      "description": "Shoes",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25,
      "type": "purchase"
    },
    {
      "id": "10002",
      "description": "Return fee",
      "unitPrice": 25,
      "quantity": 1,
      "vat": 25,
      "type": "fee"
    }
  ]
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Part refund by amount

You can also perform a partial refund by amount only. This will result in a new line item on the order with a negative value.
The adjustment amount will be applied to the most recent capture available on the order.

The 'description' field can be used to provide a descriptive text on the adjustment. If omitted, left blank or null a default value will be used.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 285.0,
  "description": "refund description",
  "actionReference": "test-refundref-123"
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

### Replacement article

To replace a refunded article, add an article of type 'replacement' without increasing the total order amount.

<Tabs defaultValue="req" values={[
{ label: 'Request', value: 'req', },
{ label: 'Response', value: 'res', }
]}>

<TabItem value="req">

```http
POST /manage/orders/{{orderId}}/refund HTTP/1.1
Host: api.uat.walleydev.com // Test environment. Production uses a different hostname.
Authorization: Bearer {{accessToken}}
Content-Type: application/json

{
  "amount": 20,
  "items": [
    {
      "id": "10001",
      "description": "Shoes",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25,
      "type": "purchase"
    },
    {
      "id": "10002",
      "description": "Shoes",
      "unitPrice": -80,
      "quantity": 1,
      "vat": 25,
      "type": "replacement"
    }
  ]
}
```

</TabItem>

<TabItem value="res">

```http
HTTP/1.1 202 Accepted
Location: /manage/orders/1b1f5ef6-92n1-4b46-b1dc-ae2e00c4c315

/* No body */
```

</TabItem>
</Tabs>

## Data Model

### Request

#### Request path

| Path        | Required | Explanation                                              |
| ----------- | -------- | -------------------------------------------------------- |
| **orderId** | Yes      | The id of the order where a refund is to be carried out |

#### Request headers

| Header            | Required | Explanation                                                                                                             |
| ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------- |
| **Authorization** | Yes      | See [Authentication](/docs/manage/getting-started/authentication) for how to generate the Bearer token value |

#### Request body

| Property            | Required | Explanation                                                                                       | Type   | Notes                                                                                 |
| ------------------- | -------- | ------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------- |
| **amount**          | Yes      | The amount to refund. Must match provided total summary of order items being refunded.            | number | Maximum 2 decimals                                                                    |
| **description**     | No       | A description for the refund. This will be visible in the order history and on the invoice.       | string | Visible on invoices if applicable. Maximum 50 characters                              |
| **actionReference** | No       | A reference to this specific refund. This will be visible on settlement files for reconciliation. | string | This will appear as a data property on the settlement report. Maximum 255 characters. |
| **items**           | No       | The article items and quantity to refund.                                                         | array  | [Refund Item](/docs/manage/orders/models/refund-item)                                 |

<br />

### Response

A successful refund or part refund answers `202 Accepted` with an empty body and a `Location`
header pointing at the order.

:::note The refund is not live yet
`202` means Walley accepted the request, not that it has been applied. Reading the order back right
away usually returns the old version. See
[Asynchronous operations](/docs/manage/concepts/asynchronous-operations) for how to read the result
and retry safely.
:::

#### Possible responses

| Http status code | Description                                                                          |
| ---------------- | ------------------------------------------------------------------------------------ |
| 202              | Refund accepted                                                                      |
| 401              | Token missing, expired, or invalid                                                   |
| 403              | No permission for this store, or the order has not finished syncing                  |
| 404              | Order not found, or the order has not finished syncing                               |
| 409              | A request with the same idempotency key is already in progress                       |
| 422              | Validation or state error. See [error codes](/docs/manage/orders/refund#error-codes) |

See [Errors](/docs/manage/errors) for what to do about each of these.

<br />

### Error codes

| Code                                                    | Message                                                                                                                                                 |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| REFUND_AMOUNT_MUST_BE_POSITIVE                          | The amount that is refunded cant have a negative value                                                                                                  |
| REFUND_AMOUNT_MUST_MATCH_SUM_OF_ARTICLES                | When items are provided, amount must equal to total sum of the items                                                                                    |
| REFUND_DESCRIPTION_TOO_LONG                             | Description have a max limit of 50 characters                                                                                                           |
| REFUND_ORDER_ALREADY_FULLY_REFUNDED                     | You cannot refund an already fully refunded order                                                                                                       |
| REFUND_UNMATCHED_RETURN_ARTICLES                        | Items provided for part refund can't be found on order. The provided values for id, description and unitprice must match the order item values exactly. |
| REFUND_AMOUNT_HAS_TOO_MANY_DECIMALS                     | The amount to be refunded has too many decimals                                                                                                         |
| REFUND_VAT_HAS_TOO_MANY_DECIMALS                        | The VAT rate given has too many decimals                                                                                                                |
| REFUND_ITEM_ID_TOO_LONG                                 | Item id has a max limit of 50 characters                                                                                                                |
| REFUND_ITEM_DESCRIPTION_TOO_LONG                        | Item description has a max limit of 50 characters                                                                                                       |
| REFUND_ITEM_QUANTITY_MUST_BE_POSITIVE                   | Item quantity must be positive                                                                                                                          |
| REFUND_ITEM_UNITPRICE_HAS_TOO_MANY_DECIMALS             | Item Unit Price has too many decimals                                                                                                                   |
| REFUND_ITEM_FEE_OR_DISCOUNT_ID_AND_DESCRIPTION_REQUIRED | Fees and discounts must have an id and a description                                                                                                    |
| REFUND_REPLACEMENT_ITEM_QUANTITY_INVALID                | When processing a refund and a replacement for the same item within a single request, the replacement quantity cannot exceed the refund quantity        |

<Idempotency />
