---
title: "Remove Orders from a Route"
method: POST
path: "/routes/{id}/remove-orders"
tags: ["Routes"]
---

# Remove Orders from a Route

`POST /routes/{id}/remove-orders`

## Request

- Base URL: `https://api.smartroutes.io/v2`
- URL: `https://api.smartroutes.io/v2/routes/{id}/remove-orders`
- Auth: none declared

Bulk-remove orders from a single route. The orders drop back to unrouted (their status returns to `OPEN`); they are not moved to another route. This is a partial-success bulk operation returning `{ orders, errors }` (the same envelope as `POST /orders`): one un-removable order never fails the rest of the batch.

The route id is given in the path (`/routes/{id}/remove-orders`) and scopes the whole call — every order must be on that route. Each order is identified by `id` (depot-scoped, preferred) and/or `order_number` — at least one is required per entry; if both are given they must resolve to the same order. An order that is not on the given route is reported as `NOT_ON_ROUTE`.

`orders` and `errors` are NOT mutually exclusive. `orders` lists every order that resolved to a real record, each with the `stops` it was taken off (`{ id, route: { id } }`) — an empty `stops` array means nothing was removed from it. `errors` is a parallel list of problems; an order that exists but could not be removed (e.g. it is on a dispatched route, or not on the given route) appears in BOTH `orders` (with empty `stops`) and `errors`. An order reference that does not resolve at all (`ORDER_NOT_FOUND`) appears only in `errors`.

Each `errors` entry is a `{ name, description, details }` envelope where `name` is the failure reason and `details` carries at least the `id` / `order_number`. Failure `name`s include `ORDER_NOT_FOUND`, `ID_NUMBER_MISMATCH`, `NOT_ON_ROUTE`, `ROUTE_DISPATCHED`, `ORDER_COMPLETED`, `STOP_REBUILD_FAILED`, `STALE_VISIT` and `REMOVAL_FAILED`. By default orders on dispatched (live) routes are reported as `ROUTE_DISPATCHED`; set `settings.allow_dispatched` to `true` to edit live routes.

Set `settings.reoptimize` to `true` to re-sequence each affected route after the removal. This runs synchronously — the request blocks until each affected route has been solved and applied, so it can take seconds to minutes. The removal is applied first and the affected route is then re-sequenced. A reoptimised order is returned in `orders` with the `stops` it was taken off, the same as a normal removal. If the removal itself fails the order is reported with `REMOVAL_FAILED` (as in a non-reoptimise call); if only the re-sequencing step fails after the order was already removed, the order still counts as removed (returned in `orders`) and the re-sequencing failure is not surfaced per order.

Multi-order (consolidated) stops are handled per stop: if every order on the stop is being removed the whole stop is deleted, otherwise the stop is kept and rebuilt with just the remaining orders (the removed order drops to `OPEN`, the others are unaffected). In the rare case the remaining orders cannot be re-consolidated into a single stop, that order is reported with `STOP_REBUILD_FAILED` and the stop is left untouched.

## Path parameters

- `id` integer, required

## Request body

- object
  - `orders` object[], required: 1..10 order references to remove.
    - `id` integer: Order id (depot-scoped). Preferred when present.
    - `order_number` string: Order number. Used when `id` is absent.
  - `settings` object
    - `allow_dispatched` boolean: When false (default) orders on dispatched routes are skipped (`ROUTE_DISPATCHED`). When true, dispatched routes are edited.
    - `reoptimize` boolean: When true, each affected route is re-sequenced after the removal. This runs synchronously: the request blocks until the route has been solved and applied, so it can take seconds to minutes. The removal is applied first; if the re-sequencing step then fails, the order still counts as removed (returned in `orders`) and the re-sequencing failure is not surfaced. A failure to remove the order is reported with `REMOVAL_FAILED`, as in a non-reoptimise call.

## Response `200`

Bulk result. `orders` lists every resolved order (with the stops it was taken off); `errors` is a parallel list of problems and may reference an order also present in `orders`. Returned for fully-successful and mixed batches alike.

- object
  - `orders` object[]: Every order that resolved to a real record. An empty `stops` array means nothing was removed from it (look it up in `errors` for the reason).
    - `id` integer: Order id.
    - `order_number` string: Order number.
    - `stops` object[]: The stop(s) the order was taken off; empty when nothing was removed.
      - `id` integer: Stop (visit) id the order was removed from.
      - `route` object
        - `id` integer: Route id the stop belonged to.
  - `errors` object[]: Orders that could not be removed.
    - `name` string: Failure reason code (e.g. `ROUTE_DISPATCHED`, `NOT_ON_ROUTE`).
    - `description` string: Human-readable explanation.
    - `details` object: At least `id` and `order_number`; may carry extra context (e.g. `route_id`, `route_ids`).
      - `id` integer, nullable
      - `order_number` string, nullable

## Other responses

- `400`: Invalid input. The request body failed validation.
- `403`: Forbidden. Returned for rate-limit exhaustion (`name = FORBIDDEN`, with `details.retry_after_seconds` and `Retry-After` header) and permission gate failures (`name = PERMISSION`). Inspect `name` to disambiguate. Send `x-sr-api-features: rate-limit-429` to receive `429 RATE_LIMIT_EXCEEDED` for the rate-limit case instead, leaving `403` to mean permission failures only — see [API Features](#section/Getting-started/API-Features).
- `404`: The requested resource was not found.
- `429`: Rate limit exceeded (`name = RATE_LIMIT_EXCEEDED`). **Only returned to callers that opt in** with the `x-sr-api-features: rate-limit-429` request header; without it the same condition returns `403` with `name = FORBIDDEN` and an otherwise identical body. See [API Features](#section/Getting-started/API-Features).
- `500`: An unexpected server error occurred. The body carries only `name` and `description`: internal details are never returned.

---

[API](https://skmtc.dev/smartroutes/apis/smartroutes-api.md) · [All operations](https://skmtc.dev/smartroutes/apis/smartroutes-api/llms.txt) · [OpenAPI document](https://skmtc.dev/smartroutes/apis/smartroutes-api/revisions/a7ea507afac7?raw)
