---
title: "Add Vehicle"
method: POST
path: "/vehicles"
tags: ["Vehicles"]
---

# Add Vehicle

`POST /vehicles`

## Request

- Base URL: `https://api.smartroutes.io/v2`
- URL: `https://api.smartroutes.io/v2/vehicles`
- Auth: none declared

Adds a vehicle to your depot's fleet so it can be used when building plans. The new vehicle is returned under `vehicle`, in the same shape as `GET /vehicles/{id}`.

- `name` (up to 30 characters), `availability` and `start_location` are required. `start_location` and `end_location` accept `depot` or `other`. With `other`, you must send the matching `*_lat` and `*_lng`. Addresses are stored as given and are not geocoded.
- With `availability: shift`, `shift_start` must be before `shift_end` (24-hour `HH:mm`). With `break: true`, `break_start`, `break_end` and `break_duration` are all required, and `break_duration` (in minutes) must be shorter than the break window.
- `capacities` are matched by `id` against your depot's capacity types (see `GET /capacities`). Unknown IDs are dropped without an error. Any `skills` name not yet in your organisation is created. Names match exactly and are case-sensitive.
- `active` defaults to `true`.

Each organisation has a vehicle limit across all its depots. Adding a vehicle beyond that limit returns `400 INVALID_INPUT`. This endpoint supports [Idempotency](#section/Getting-started/Idempotency).

## Headers

- `idempotency-key` string

## Request body

- object: Request body for creating a new vehicle.
  - `name` string: Name of the vehicle.
  - `availability` 'shift' | 'full_day' | 'always', required: Availability status of the vehicle.
  - `shift_start` string, time, nullable: Start time of the vehicle's shift (if availability is 'shift').
  - `shift_end` string, time, nullable: End time of the vehicle's shift (if availability is 'shift').
  - `start_location` 'depot' | 'other' | 'app-location', required: Location type where the vehicle starts.
  - `start_address` string, nullable: Address where the vehicle starts (if location is 'other').
  - `start_lng` number, nullable: Longitude of the starting location (if location is 'other').
  - `start_lat` number, nullable: Latitude of the starting location (if location is 'other').
  - `end_location` 'depot' | 'other' | 'none', required: Location type where the vehicle ends.
  - `end_address` string, nullable: Address where the vehicle ends (if location is 'other').
  - `end_lng` number, nullable: Longitude of the ending location (if location is 'other').
  - `end_lat` number, nullable: Latitude of the ending location (if location is 'other').
  - `break` boolean: Flag indicating whether the vehicle has a break.
  - `break_start` string, time, nullable: Start time of the vehicle's break (if it has a break).
  - `break_end` string, time, nullable: End time of the vehicle's break (if it has a break).
  - `break_duration` number, nullable: Duration of the vehicle's break in minutes (if it has a break).
  - `active` boolean: Flag indicating whether the vehicle is active.
  - `skills` string[]: Array of skills associated with the vehicle.
  - `capacities` object[]: Array of capacities associated with the vehicle.
    - `id` integer, required: Id of capacity (e.g., 1, 2).
    - `capacity` number, float, required: Capacity value for the specified type.

## Response `201`

Successful response

- VehicleResponse
  - `vehicle` Vehicle, required: A depot vehicle. Property set is the union of fields returned by list and get-by-id paths; conditional fields (shift_*, start_address/lat/lng, end_address/lat/lng, break_*) populate only when the corresponding mode is selected. Source of truth: `getExternalModel` in `src/vehicles/vehicles.service.js`.
    - `id` integer
    - `name` string
    - `active` boolean
    - `availability` 'shift' | 'full_day' | 'always'
    - `start_location` 'depot' | 'other' | 'app-location'
    - `end_location` 'depot' | 'other' | 'none'
    - `capacities` object[]
      - `id` integer
      - `type` string
      - `capacity` number
    - `skills` string[]
    - `shift` object[]: Weekly shift schedule. Each entry is one row of vehicle_shifts (enabled, availability, shift_start, shift_end, force_shift_start, max_route_duration, day_of_week) plus a nested vehicle_breaks array.
      - `enabled` boolean
      - `availability` 'shift' | 'full_day' | 'always'
      - `shift_start` string, nullable: HH:mm.
      - `shift_end` string, nullable: HH:mm.
      - `force_shift_start` boolean
      - `max_route_duration` integer, nullable: Minutes.
      - `day_of_week` 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY' | 'null', nullable
      - `vehicle_breaks` object[]
        - `enabled` boolean
        - `break_start` string, nullable: HH:mm.
        - `break_end` string, nullable: HH:mm.
        - `break_duration` integer, nullable: Minutes.
    - `created` string, date-time
    - `updated` string, date-time
    - `shift_start` string, nullable: HH:mm. Present when availability == 'shift'.
    - `shift_end` string, nullable: HH:mm. Present when availability == 'shift'.
    - `start_address` string, nullable: Present when start_location == 'other'.
    - `start_lat` number, nullable
    - `start_lng` number, nullable
    - `end_address` string, nullable: Present when end_location == 'other'.
    - `end_lat` number, nullable
    - `end_lng` number, nullable
    - `break` boolean
    - `break_start` string, nullable: HH:mm. Present when break == true.
    - `break_end` string, nullable: HH:mm. Present when break == true.
    - `break_duration` number, nullable: Minutes. Present when break == true.

## 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).
- `409`: A request with this idempotency key is already in progress. Retry after the period given in the `Retry-After` header.
- `422`: The same idempotency key was used with a different request body for this endpoint.
- `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)
