---
title: "Update Customer by ID"
method: PUT
path: "/customers/{id}"
tags: ["Customers"]
---

# Update Customer by ID

`PUT /customers/{id}`

## Request

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

Updates one customer in your depot. This is a partial update: only the fields you send change. For `capacities`, `skills`, `tags`, `time_windows` and `custom_fields`, sending the array replaces the customer's whole set (an empty array clears it), and leaving it out keeps the existing set. Capacities, skills and tags that don't exist in your depot or organisation are dropped without an error. Custom fields are matched by `id` only.

- Every request must include either `address` or both `lat` and `lng`, even when you are only changing other fields.
- Changing `address` without sending coordinates re-geocodes the customer. If geocoding fails, the update is still saved and the failure is reported as a `GEOCODING_FAILED` entry in the response's `errors` array.
- Setting `account` to a value another customer in your depot already uses returns `400 INVALID_INPUT`.

The response holds the updated customer under `customer` (the same shape as `GET /customers/{id}`) along with an `errors` array.

## Path parameters

- `id` string, required

## Request body

- object: Details of the customer to be updated.
  - `name` string: Name of the customer.
  - `account` string: Account number of the customer.
  - `address` string: Address of the customer.
  - `postcode` string: Postcode for the customer address.
  - `lat` number: Latitude of the customer location.
  - `lng` number: Longitude of the customer location.
  - `phone` string: Contact number of the customer.
  - `email` string, email: Email of the customer.
  - `duration` number: Duration for customer interaction in minutes.
  - `notes` string: Notes for customer interaction.
  - `time_windows` object[]: List of time windows for the customer.
    - `from` string, time, required: Start time of the time window.
    - `to` string, time, required: End time of the time window.
  - `skills` string[]: List of required skills for the customer.
  - `tags` string[]: List of tags for the customer
  - `capacities` object[]: List of capacities for the customer.
    - `id` integer, required: Id of capacity (e.g., 1, 2).
    - `capacity` number, float, required: Capacity value for the specified type.
  - `custom_fields` object[]: List custom fields for the customer
    - `id` integer: Id of custom field (e.g., 1, 2).
    - `value` string: New custom field value

## Response `200`

Successful response

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