> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stateset.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Returns Workflow

> The RMA state machine — authorise, receive, inspect, refund, close.

# Returns Workflow

Returns are a state machine, not a flag. Each transition is a distinct call, so the record is
auditable end to end.

```
create ──▶ approve ──▶ markReceived ──▶ complete
   │          │
   │          └──▶ reject
   └──▶ cancel
```

## 1. Validate eligibility

Check the return window, item condition, and item eligibility **before** creating the
authorisation. Creating an RMA the policy would reject leaves a record you then have to unwind.

## 2. Create the return authorisation

```js theme={null}
import { Commerce } from '@stateset/embedded';
const commerce = new Commerce('./store.db');

const rma = await commerce.returns.create({
  orderId: 'ord_9412',
  lineItems: [{ sku: 'SHOE-RED-10', quantity: 1, reasonCode: 'damaged' }],
});
```

## 3. Approve or reject

```js theme={null}
await commerce.returns.approve(rma.id);
// or
await commerce.returns.reject(rma.id, { reason: 'outside return window' });
```

## 4. Add tracking, then receive

```js theme={null}
await commerce.returns.addTracking(rma.id, {
  carrier: 'usps',
  trackingNumber: '9400111899223817463149',
});

// when the parcel arrives
await commerce.returns.markReceived(rma.id);
```

<Note>
  `markReceived` is the point the return becomes real — inventory and financial consequences follow
  from it, not from `approve`. Approving an RMA that never arrives costs you nothing.
</Note>

## 5. Inspect and complete

Inspection decides restock, refurbish, or reject. Then:

```js theme={null}
await commerce.returns.complete(rma.id);
```

`complete` finalises the record and settles order, inventory, and financial state together.

## Cancelling

```js theme={null}
await commerce.returns.cancel(rma.id);
```

## Finding returns

```js theme={null}
await commerce.returns.listForOrder('ord_9412');
await commerce.returns.listForCustomer('cus_1042');
await commerce.returns.listPending();          // the work queue
await commerce.returns.get(rma.id);
await commerce.returns.count();
```

<Tip>
  `listPending()` is the operational view — everything authorised but not yet resolved. That's the
  queue a returns agent should work from.
</Tip>

## Why the transitions are separate

A single `status` field you overwrite loses the history. Because each step is its own call, the
record answers *when* it was approved, *when* the parcel landed, and *who* completed it — which is
what a chargeback or an audit actually asks.

<Note>
  `update_return` is deliberately **not** exposed as a single tool: its input is complex and
  unbounded. The status-transition methods above cover the practical paths.
</Note>

## Related

* [Order Lifecycle](/stateset-icommerce/stateset-icommerce-order-lifecycle)
* [Returns Quickstart](/guides/returns-quickstart)
* [Finance & Accounting](/stateset-icommerce/stateset-icommerce-finance) — where refunds land
