# Update order status

Moves an order under the same rules as the merchant dashboard. It never records a payment and never refunds.

```http
PATCH https://larm.sa/stores/{storeId}/v1/orders/{id}/status
```

Scope: `orders.status:write`

`completed` closes a paid order and delivers any codes held for review. An unpaid order stays unpaid: moving it to `processing` or `completed` returns `ORDER_NOT_PAID`, and only the merchant can confirm a bank transfer. `cancelled` or `returned` on a completed order changes the status the merchant sees and moves no money. Refunds stay with the merchant. See [Working with orders](/guides/orders).

## Path parameters

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | string | yes |  |


## Request body

| Field | Type | Required | Description |
|---|---|---|---|
| `status` | string | yes | The status as the merchant sees it, under the same rules as the dashboard. One of: `processing`, `completed`, `cancelled`, `returned`. |


## Response

| Field | Type | Required | Description |
|---|---|---|---|
| `data` | object | yes |  |
| `data.order_id` | string | no |  |
| `data.status` | string | no | One of: `pending`, `processing`, `completed`, `cancelled`, `returned`. |
| `data.payment_status` | string | no | One of: `unpaid`, `paid`, `refunded`. |
| `data.updated_at` | string (date-time) | no |  |
| `execution` | object | no | Who executed the request: the app, version, installation and store. Field names here are camelCase. |
| `execution.appId` | string (uuid) | no |  |
| `execution.versionId` | string (uuid) | no |  |
| `execution.installationId` | string (uuid) | no |  |
| `execution.storeId` | string (uuid) | no |  |
| `execution.requestId` | string (uuid) | no |  |
| `execution.generation` | integer | no |  |
| `execution.routeEpoch` | integer | no |  |
| `execution.appAuthEpoch` | integer | no |  |
| `execution.grantRevision` | integer | no |  |
| `meta` | object | yes |  |
| `meta.request_id` | string (uuid) | no | The request ID; include it in any support request. |


## Example request

```bash
curl -X PATCH "https://larm.sa/stores/$STORE_ID/v1/orders/200123/status" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "completed" }'
```


## Example response (200)

```json
{
  "data": {
    "order_id": "200123",
    "status": "completed",
    "payment_status": "paid",
    "updated_at": "2026-11-02T10:04:00.000Z"
  },
  "execution": {
    "appId": "1f2e3d4c-5b6a-4978-8695-a4b3c2d1e0f9",
    "versionId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "installationId": "c7e4a1f2-6b3d-4e8a-9c05-1d2f3a4b5c6d",
    "storeId": "5b1d7a62-0c4e-4f38-9a51-2e7b3c9d8f10",
    "requestId": "3f0c2b8e-7a51-4c1e-9d0a-5b6f1e2d4c3a",
    "generation": 1,
    "routeEpoch": 4,
    "appAuthEpoch": 1,
    "grantRevision": 2
  },
  "meta": {
    "request_id": "3f0c2b8e-7a51-4c1e-9d0a-5b6f1e2d4c3a"
  }
}
```


## Errors

| HTTP | Code | Meaning |
|---|---|---|
| 404 | `RESOURCE_NOT_FOUND` | The ID does not exist in this store. |
| 409 | `ORDER_NOT_PAID` | The order is not paid, so it cannot move to processing or completed. |
| 409 | `BANK_TRANSFER_CONFIRM_REQUIRED` | The order waits for a bank transfer only the merchant can confirm. |
| 409 | `ORDER_ADMINISTRATIVELY_CANCELLED` | The merchant cancelled this completed order. Bring it back to completed first. |
| 409 | `INVALID_ORDER_TRANSITION` | The order cannot move from its current status to this one. |
| 409 | `INVALID_ADMINISTRATIVE_TRANSITION` | Only a paid order can change this way. |
| 409 | `SHIPPING_IN_PROGRESS` | A shipment is being created for this order. Wait for it to finish. |
| 409 | `STORE_RULE_REFUSED` | A store rule refused the command. Read the resource before you try again. |
| 422 | `INVALID_ORDER_STATUS` | Unknown status. |
| 403 | `SCOPE_REQUIRED` | The token does not carry the required scope. |
| 503 | `APPS_SCOPE_RUNTIME_NOT_READY` | The resource is not enabled on this merchant's store yet. |
