---
title: "Dispatch a Plan"
method: POST
path: "/plans/{id}/dispatch"
tags: ["Plans"]
---

# Dispatch a Plan

`POST /plans/{id}/dispatch`

## Request

- Base URL: `https://api.smartroutes.io/v2`
- URL: `https://api.smartroutes.io/v2/plans/{id}/dispatch`
- Auth: none declared

Dispatch every undispatched route on a plan. Each route is flagged as dispatched, its orders move to `ROUTED`, customer tracking portals are minted, superseded notification tasks are cancelled (with SMS credit refunded), planned-start notifications are scheduled, and each route is pushed to its assigned driver's app. Once every route on the plan is dispatched, the plan is marked dispatched and a [`plans.dispatched`](#tag/Webhooks/operation/plans.dispatched) webhook is published.

As with `GET` and `DELETE /plans/{id}`, the id may be a plan id or the id of that plan's active solution. A solution id that is not the plan's active solution is rejected with `400`.

Routes already dispatched individually are skipped and the rest are dispatched — `routes` in the response lists only the routes this call dispatched. A plan still being optimised is rejected with `400`.

Dispatch is synchronous and can take up to two minutes: the response is returned only once every side effect has run (order statuses, customer tracking portals, notification scheduling and SMS credit refunds, driver push, external-system export). A `200` means the dispatch is live — there is nothing to poll.

The request takes **no body**. Dispatch is as-planned: no vehicle, driver or date override, and no re-optimisation.

Dispatch is **not idempotent and not reversible**. A repeat call answers `409 ALREADY_DISPATCHED`, and there is no endpoint to undispatch. If the call times out (`503`), re-post it: a `409` means the first attempt succeeded.

## Path parameters

- `id` integer, required

## Response `200`

The plan's routes are dispatched.

- object
  - `plan` object
    - `id` integer: ID of the plan — not the solution id, even when a solution id was given.
    - `dispatched` boolean: `true` when every route on the plan is now dispatched. `false` means routes remain undispatched on the plan, which is only reachable if some were dispatched individually first.
    - `routes` object[]: The routes this call dispatched. Routes already dispatched before the call are not listed.
      - `id` integer: ID of the dispatched route.

## 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.
- `409`: The route or plan is already dispatched. Dispatch is not repeatable and cannot be undone.
- `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.
- `503`: The dispatch could not be completed — a downstream service was unreachable, timed out, or failed. The dispatch may or may not have been applied; re-post to find out, as a `409` means the first attempt succeeded.

---

[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)
