> For the complete documentation index, see [llms.txt](https://docs.fulfillmenttools.com/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fulfillmenttools.com/documentation/by-pillar/store-operations/returns.md).

# Returns

{% hint style="info" %}
This article focuses on the returns process for developers. For information on the returns in the store operations process, see the [Store Operations app](/documentation/apps/store-operations-app.md) section.
{% endhint %}

A return is when a consumer sends a purchased product back to the retailer for a refund, exchange, or store credit. The return process typically involves either bringing the items to the store in person or initiating an online return.

There are two types of return:

* Announced returns (the consumer notifies the retailer in advance about the return)
* Unannounced returns (the consumer returns an item without prior notification)

For both types, an item return job needs to include items that could be returned from the original order.

## Item return job

An `itemReturnJob` is the main entity in the returns process. It contains all potential `itemReturns` associated with a placed order. It encompasses all items eligible for return (and those not eligible) and tracks the items actually returned. During interactions with the `itemReturnJob`, validations ensure that only items handed over in the given order can be returned in the handed-over quantities.

An `itemReturnJob` is automatically created after the [handover](/documentation/by-pillar/store-operations/handover.md) process. fulfillmenttools then sends a notification with the `ITEM_RETURN_JOB_CREATED` event. If the handover feature isn't used, the `itemReturnJob` can be created via the [item return jobs REST API](broken://pages/fb3987e580a175fa8bb9b78cb97a79e11d2050c0).

The `itemReturnJob` starts with an `OPEN` status. The `returnableLineItems` list contains all handover items eligible for return. The `itemReturnJob` includes all items from all handovers related to the original order, even if the order was split into multiple pick jobs.

Use the endpoint below to get all item return jobs:

```http
GET https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs
```

## Item return

An `itemReturn` represents all items actually returned within the associated `itemReturnJob`. You must have a valid `itemReturnJob` before creating an `itemReturn`.

While adding or updating an `itemReturn` within an existing `itemReturnJob`, item validations ensure that the returned quantity doesn't exceed the delivered and previously returned amounts.

Line items are returned by creating a new `itemReturn` entity within an existing `itemReturnJob`. This is done using the following API call:

{% tabs %}
{% tab title="Endpoint" %}

```http
POST https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "itemReturnForCreation": {
    "status": "ANNOUNCED",
    "returnFacilityRef": "{YOUR_FACILITY_ID_WHERE_ITEMS_ARE_RETURNED_TO}",
    "tenantOrderId": "{YOUR_TENANT_ORDER_ID}",
    "returnedLineItems": [
      {
        "itemConditionComment": "Logo print is coming off the T-shirt",
        "tenantArticleId": "TSHIRT-NERDHERD-LOGO",
        "status": "OPEN"
      }
    ]
  },
  "itemReturnJobVersion": 1
}
```

{% endtab %}
{% endtabs %}

This call creates a preannounced `itemReturn` with an initial status of `OPEN`, which can be updated later as required. Entries in `returnedLineItems` reference line items from the `returnableLineItems` array of the parent `itemReturnJob`, and entries in `returnedNotReturnableLineItems` reference line items from its `notReturnableLineItems` array. An `itemReturn` must contain at least one entry in either array. The request must also include the current `itemReturnJobVersion` to prevent concurrent modifications.

The `status` of an `itemReturnJob` doesn't automatically change to `FINISHED`, even if all of its `returnedLineItems` are `ACCEPTED`. You must update the `itemReturnJob` status explicitly via an API call. This action triggers an `ITEM_RETURN_JOB_UPDATED` event.

{% hint style="warning" %}
Updating `returnedLineItems` or `returnedNotReturnableLineItems` replaces the whole array. Entries that aren't included in the request are removed.
{% endhint %}

### Triggering a refund

A refund is triggered when the `refund` and `status` fields of a specific `returnedLineItem` are updated. This is accomplished using the following `PATCH` request, which requires the current `itemReturnJobVersion`. For more details, see the [Returns endpoints article](/documentation/by-pillar/store-operations/returns/returns-endpoints.md).

{% tabs %}
{% tab title="Endpoint" %}

```http
PATCH https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns/{YOUR_ITEM_RETURN_ID}/returnedlineitems/{YOUR_RETURNED_LINE_ITEM_ID}
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "status": "OPEN",
  "refund": {
    "status": "OPEN",
    "price": {
      "value": 19.95,
      "currency": "EUR"
    }
  },
  "itemReturnJobVersion": 2
}
```

{% endtab %}
{% endtabs %}

You can also trigger the refund event via [Backoffice](/documentation/backoffice/network-view/orders/returns.md). You'll need to have the `allowTriggerRefund` setting in the [return configuration](#return-configuration) set to `true` to do this.

{% hint style="info" %}
A refund can only be triggered for entries in `returnedLineItems`. Entries in `returnedNotReturnableLineItems` don't have a `refund` field. To refund a non-returnable item, see the [Accept or reject non-returnable items section](#accept-or-reject-non-returnable-items).
{% endhint %}

## Returnable and non-returnable items

Some items can't be returned, for example, customized items or items from special offers. For this reason, an `itemReturnJob` has two arrays: `returnableLineItems` and `notReturnableLineItems`.

When fulfillmenttools automatically creates an `itemReturnJob`, it fills both arrays. By default, fulfillmenttools places items in `returnableLineItems`. An item is placed in `notReturnableLineItems` only if it was part of a related service job with the `itemsReturnable` flag set to `false`.

If items are marked as handed over during the handover process with a `handedOverQuantity` of at least `1`, the `delivered` field corresponds to the `handedOverQuantity`. If there is no handover job, or none of its items have a `handedOverQuantity` of at least `1`, fulfillmenttools fills the arrays with the items from the related pick job. In this case, the `delivered` field corresponds to the `picked` quantity.

The array determines whether a line item is returnable. The `returnable` field holds the quantity that can still be returned. For line items in `returnableLineItems`, this is the difference between `delivered` and `returned`. For line items in `notReturnableLineItems`, it's always `0`.

An `itemReturn` reflects the same split: `returnedLineItems` contains returned items from `returnableLineItems`, and `returnedNotReturnableLineItems` contains returned items from `notReturnableLineItems`. The `returned` field counts the returned quantity regardless of which array records the returned item.

### Move line items between arrays

A line item's array isn't fixed. If a non-returnable item is to be accepted as a regular return, for example, as a goodwill gesture, its line item can be moved to `returnableLineItems`. From then on, it's handled like any other returnable item, and a refund can be triggered for it. Line items can also be moved in the opposite direction. Both directions use [actions](/documentation/by-pillar/store-operations/returns/returns-endpoints.md#post-api-itemreturnjobs-itemreturnjobid-actions) on the `itemReturnJob`: `CHANGE_LINE_ITEMS_TO_RETURNABLE_IN_ITEM_RETURN_JOB` and `CHANGE_LINE_ITEMS_TO_NOT_RETURNABLE_IN_ITEM_RETURN_JOB`.

As long as a line item is used in an item return, it can't be moved, even after the item return is finished. To move it, remove it from the item return or cancel the item return. Once the `itemReturnJob` is finished, its item returns can't be changed anymore, and the line item can no longer be removed. Other line items of the same `itemReturnJob` aren't affected and can still be moved. How to handle a non-returnable item that has already been returned is described in the [Accept or reject non-returnable items section](#accept-or-reject-non-returnable-items).

After a move, the `returnable` field matches the target array: `0` in `notReturnableLineItems`, and the difference between `delivered` and `returned` in `returnableLineItems`.

The following request moves a line item to `returnableLineItems`:

{% tabs %}
{% tab title="Endpoint" %}

```http
POST https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/actions
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "name": "CHANGE_LINE_ITEMS_TO_RETURNABLE_IN_ITEM_RETURN_JOB",
  "version": 3,
  "lineItemIds": ["{YOUR_LINE_ITEM_ID}"]
}
```

{% endtab %}
{% endtabs %}

### Accept or reject non-returnable items

A returned non-returnable item is either rejected or accepted. Both decisions update the item's status in `returnedNotReturnableLineItems`. The following request rejects the item:

{% tabs %}
{% tab title="Endpoint" %}

```http
PATCH https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns/{YOUR_ITEM_RETURN_ID}/returnednotreturnablelineitems/{YOUR_RETURNED_NOT_RETURNABLE_LINE_ITEM_ID}
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "status": "REJECTED",
  "itemReturnJobVersion": 2
}
```

{% endtab %}
{% endtabs %}

Setting the status to `ACCEPTED` instead records that the item is taken back. The item remains non-returnable: its `returnable` field stays `0`, and no refund can be triggered for it. You can still change the status later.

{% hint style="warning" %}
Systems that consume the `ITEM_RETURN_JOB_UPDATED` event receive the `ACCEPTED` status for items in both arrays. To avoid refunding a non-returnable item, these systems need to distinguish between `returnedLineItems` and `returnedNotReturnableLineItems`.
{% endhint %}

To accept a non-returnable item as a regular return with a refund, for example, as a goodwill gesture, the item has to become returnable first. To do that, follow the steps below:

{% stepper %}
{% step %}
**Remove the item from the item return**

Replace the returned non-returnable line items of the item return without the item.

{% tabs %}
{% tab title="Endpoint" %}

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns/{YOUR_ITEM_RETURN_ID}/returnednotreturnablelineitems
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "itemReturnJobVersion": 2,
  "returnedNotReturnableLineItems": []
}
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Move the line item to the returnable items**

Move the line item to `returnableLineItems`.

{% tabs %}
{% tab title="Endpoint" %}

```http
POST https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/actions
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "name": "CHANGE_LINE_ITEMS_TO_RETURNABLE_IN_ITEM_RETURN_JOB",
  "version": 3,
  "lineItemIds": ["{YOUR_LINE_ITEM_ID}"]
}
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}
**Add the item to the returned line items**

Add the item to `returnedLineItems` with the status `ACCEPTED`. The request replaces all entries in `returnedLineItems`, so include the existing entries as well. Otherwise, they're removed.

{% tabs %}
{% tab title="Endpoint" %}

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns/{YOUR_ITEM_RETURN_ID}/returnedlineitems
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "itemReturnJobVersion": 4,
  "returnedLineItems": [
    {
      "itemReturnJobLineItemRef": "{EXISTING_LINE_ITEM_ID}",
      "status": "ACCEPTED"
    },
    {
      "itemReturnJobLineItemRef": "{MOVED_LINE_ITEM_ID}",
      "status": "ACCEPTED"
    }
  ]
}
```

{% endtab %}
{% endtabs %}
{% endstep %}
{% endstepper %}

A refund can then be triggered as described in the [Triggering a refund section](#triggering-a-refund).

## Return configuration

The [return configuration endpoint](broken://pages/9dfa195d33b5b31055c7c141bb566bc70f015eac) lets you provide default inputs for your returns. These inputs are then displayed in the Store Operations app and Backoffice. These can be for:

* [Return reasons](#return-reasons)
* [Return item conditions](#returned-item-conditions)
* [Decision reasons](#decision-reasons)

The example below shows the endpoint you need to use to update the configuration, along with an example request that includes all three options.

{% tabs %}
{% tab title="Endpoint" %}

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/configurations/return
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "version": 1,
  "active": true,
  "availableItemConditions": [
    { "conditionLocalized": { "en_US": "Damaged" } },
    { "conditionLocalized": { "en_US": "Used" } },
    { "conditionLocalized": { "en_US": "Perfect" } } 
  ],
  "availableReturnReasons": [
    { "reasonLocalized": { "en_US": "Item doesn't fit" } },
    { "reasonLocalized": { "en_US": "Item didn't match description" } },
    { "reasonLocalized": { "en_US": "Item is damaged" } }    
  ],
  "availableDecisionReasons": [
   { "reasonLocalized": { "en_US": "Return accepted" } },    
   { "reasonLocalized": { "en_US": "Return rejected" } }, 
   { "reasonLocalized": { "en_US": "Return on hold" } }       
  ],
  "returnTypeConfiguration": {
    "type": "ITEM_RETURN"
  },
  "allowTriggerRefund": true
}
```

{% endtab %}
{% endtabs %}

You can also deactivate camera scanning by setting `RETURNING_CAMERA_SCANNING_DISABLED` to `FALSE`.

### Return reasons

Return reasons help you specify why a consumer has returned certain items as you process the return.

For example, you could add the reasons below to the [return configuration](broken://pages/9dfa195d33b5b31055c7c141bb566bc70f015eac):

* Item doesn't fit
* Item didn't match description
* Item damaged

You can pass reasons when creating an `itemReturn` through the API. Default reasons are optional when passing reasons into an `itemReturn`.

#### Default values for return reasons in the backend

Default values for return reasons in the backend aren't provided. However, you can manage return reasons on the client side. For example, in the [Store Operations app](/documentation/apps/store-operations-app/returns-beta.md), the default return reason is **No reason**. If no additional reasons are specified in the backend, the return reasons will not be displayed.

API users can use predefined return reasons or provide their own when creating or updating an `itemReturnLineItem` on an `itemReturn`.

### Returned item conditions

Upon receiving the returned item, the item's condition is assessed, eligibility is verified under the return policy, and a suitable resolution is provided (for example, a refund or store credit). This requires the ability to create a return manually.

When accepting returned items, the condition of the items can be defined. In the [Store Operations app](/documentation/apps/store-operations-app/returns-beta.md), the default condition is set to **Not damaged**. However, the backend doesn't define a default value.

Localized `itemConditions` can be added to the `returnConfiguration` via [return configuration](/documentation/by-pillar/store-operations/returns/returns-endpoints.md#put-api-configurations-return).

The translation depends on the user's locale for this endpoint and the `tenantLocaleConfiguration`.

### Decision reasons

Decision reasons allow staff to specify why a returned item was accepted, rejected, or put on hold when setting the status of a returned line item.

You can pass reasons when updating a returned line item through the API. Predefined decision reasons are optional when setting a returned line item's status.

Setting `RETURNING_DECISION_ACCEPT_PRESELECTED` to `TRUE` in the remote configuration preselects accept as the decision.

#### **Default values for decision reasons in the backend**

Default values for decision reasons in the backend aren't provided. However, you can manage decision reasons on the client side. If no decision reasons are configured in the backend, none will be displayed.

API users can use predefined decision reasons or provide their own when updating a `returnedLineItem`'s status.

## Announced returns

Announced returns are return requests a consumer registers before the physical package arrives at the facility. Announced returns include the items and details the consumer provides, such as the return reason and item condition.

The return announcement is transferred from the shop, and an `itemReturn` is created in the associated `itemReturnJob` with the status `ANNOUNCED`. This job can be updated until it is confirmed.

These details are made available in [Backoffice](/documentation/backoffice/network-view/orders/returns.md) and the [Store Operations app](/documentation/apps/store-operations-app/returns-beta.md), where announced returns can be searched for, optionally using a barcode from the return label if provided. The user can also check and, if necessary, edit those details and confirm the return.

When you confirm the return, the status changes from `ANNOUNCED` to `COMPLETED`, and you can't make further changes after confirmation.

### Create an announced return

To create and complete an announced return, follow the steps below.

{% hint style="info" %}
This example only contains returnable items.
{% endhint %}

{% stepper %}
{% step %}
**Find** **the `itemReturnJobId` for the order**

Query the `GET` endpoint using the `tenantOrderId` and `facilityId`

{% tabs %}
{% tab title="Endpoint" %}

```http
GET https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs?searchTerm={YOUR_TENANT_ORDER_ID}&facilityId={YOUR_FACILITY_ID}
```

{% endtab %}

{% tab title="Response" %}
{% code title="Response example (excerpt):" %}

```json
[
  {
    "id": "job_98765",
    "status": "OPEN",
    "tenantOrderId": "ORDER_456",
    "returnableLineItems": [
      {
        "article": {
          "tenantArticleId": "SNEAK-W-4891",
          "title": "White sneakers"
        },
        "delivered": 1,
        "returned": 0,
        "returnable": 1
      }
    ],
    "notReturnableLineItems": [],
    "itemReturns": []
  }
]
```

{% endcode %}
{% endtab %}
{% endtabs %}

From the response, take the `id` for the matching the `tenantOrderId` as the `itemReturnJobId`.
{% endstep %}

{% step %}
**Create the announced return**

Create an announced return using the below endpoint. An announced return must have the status of `ANNOUNCED`.

You need to include the reference of the facility the item(s) are being returned to in the `returnFacilityRef`, as well as at least one entry in `returnedLineItems` or `returnedNotReturnableLineItems`.

Each returned line item must include the `tenantArticleId` and a line item status (for example, `OPEN`).

`itemConditionLocalized` and `reasons` are optional.

{% tabs %}
{% tab title="Endpoint" %}

```http
POST https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/itemreturnjobs/{YOUR_ITEM_RETURN_JOB_ID}/itemreturns
```

{% endtab %}

{% tab title="Request" %}

```json
{
  "itemReturnForCreation": {
    "status": "ANNOUNCED",
    "returnFacilityRef": "FACILITY_123",
    "tenantOrderId": "ORDER_456",
    "scannableCodes": ["RETURN_LABEL_789"],
    "returnedLineItems": [
      {
        "tenantArticleId": "SNEAK-W-4891",
        "status": "OPEN",
        "scannedCodes": ["SNEAK-W-4891"],
        "itemConditionLocalized": {
          "de_DE": "Perfekt",
          "en_US": "Perfect"
        },
        "itemConditionComment": "Item doesn't fit",
        "reasons": [
          {
            "reason": "SIZE_TOO_SMALL",
            "reasonLocalized": {
              "de_DE": "Zu klein",
              "en_US": "Too small"
            },
            "comment": "Item doesn't fit"
          }
        ]
      }
    ]
  },
  "itemReturnJobVersion": 0
}
```

{% endtab %}

{% tab title="Response" %}

```json
{
  "id": "ret_12345",
  "created": "2025-08-11T08:30:00.000Z",
  "status": "ANNOUNCED",
  "returnFacilityRef": "FACILITY_123",
  "tenantOrderId": "ORDER_456",
  "returnedLineItems": [
    {
      "tenantArticleId": "a69006ba-7100-4b4d-a610-1ca28016a4eb",
      "status": "OPEN",
      "itemConditionLocalized": {
        "de_DE": "Wert",
        "en_US": "Value"
      },
      "reasons": [
        {
          "reason": "SIZE_TOO_SMALL",
          "reasonLocalized": {
            "de_DE": "Zu klein",
            "en_US": "Too small"
          },
          "comment": "Upper corner damaged"
        }
      ],
      "recordableAttributes": [
        {
          "group": "general",
          "keyLocalized": {
            "de_DE": "Land",
            "en_US": "Country"
          },
          "recordingRule": "MANDATORY",
          "value": "Germany"
        }
      ]
    }
  ],
  "itemReturnJobId": "job_98765"
}
```

{% endtab %}
{% endtabs %}

You can check the return in Backoffice. Open the **Network view** and select **Returns** in the sidebar. Then, filter by **Announced** in the **Return status**. You should see your newly created return job in the table.
{% endstep %}

{% step %}
**Edit any information before confirmation (optional)**

Edits can be made in the Returns app. You can:

* Adjust quantities.
* Replace or correct items within the same order.
* Update reasons or conditions (if applicable).
* Add missing items from the same order, if necessary.
  {% endstep %}

{% step %}
**Confirm the return using the Returns app**

* Review the item summary and details.
* Confirm the return.
* When you confirm the return, the status changes from `ANNOUNCED` to `COMPLETED`, and you can't make further changes after confirmation.
  {% endstep %}
  {% endstepper %}

## Unannounced returns

An unannounced return is when a consumer returns an item without notifying you in advance. This usually happens in a store. Use the Returns app to manage the return process. See the [Returns in the Store Operations app article](/documentation/apps/store-operations-app/returns-beta.md) for more information.


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.fulfillmenttools.com/documentation/by-pillar/store-operations/returns.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
