POST /api/v1/routes accepts an authenticated route-generation request. Send a
valid session; requests without one return 401 Unauthorized.
Each of origin and destination must be either an identifier string, such as
"saved:home" or "poi:work", or a coordinate object:
{
"origin": {"lat": 51.5, "lng": -0.1},
"destination": "poi:work",
"preferences": {
"mode": "walking",
"themes": ["heritage"],
"themeIds": ["theme-1"],
"interestThemeIds": ["interest-1"],
"avoid": ["busy-roads"],
"avoidStairs": true
}
}
Coordinates use WGS84 decimal degrees. Latitude must be between -90 and 90,
and longitude between -180 and 180, inclusive. The coordinate object must
contain only lat and lng; both values are required. The optional
preferences object accepts these fields, all of which are optional:
| Field | Type | Meaning |
|---|---|---|
mode |
string | Routing mode. |
themes |
string[] | Theme names. |
themeIds |
string[] | Theme identifiers. |
interestThemeIds |
string[] | Interest-theme identifiers. |
avoid |
string[] | Route features to avoid. |
avoidStairs |
boolean | Whether to avoid stairs. |
Each preference list (themes, themeIds, interestThemeIds, and avoid)
may contain at most 64 entries. Each string preference value, including mode
and every list entry, may contain at most 64 UTF-8 bytes. Values or lists
exceeding these limits are rejected as 400 Bad Request.
The request body rejects null origin, destination, or preferences,
boolean or array locations, coordinate objects with missing or unknown fields,
and unknown fields at the top level or in preferences. Omit preferences
when no preferences are needed; do not send it as null. These validation
failures return 400 Bad Request.
Successful submissions return 202 Accepted with a generated request ID:
{
"requestId": "<request-id>",
"status": "accepted"
}
To make retries safe, send an Idempotency-Key header containing a UUID. The
first request returns 202 Accepted with status: "accepted". Repeating the
same key with the same payload returns 202 Accepted with the original
requestId and status: "replayed". Reusing the key with a different payload
returns 409 Conflict. An invalid or empty key returns 400 Bad Request; the
header is optional. If a backend service required to accept or persist the
submission is unavailable, the endpoint returns 503 Service Unavailable.
How long a key stays replayable
An idempotency key is replayable until its record expires.
IDEMPOTENCY_TTL_HOURS sets that window on the server, defaulting to 24 hours
and clamped to between one hour and ten years, so a value outside that range is
brought back to the nearest bound rather than rejected. Sending the same key
after the window has passed starts a new request rather than replaying the old
response.
The variable, its default, and its clamp are unchanged. Operators need do nothing. Where the server reads it moved in the change that introduced the environment-seam policy, from the domain layer to a configuration adapter; that is an internal Rust API move with no deployment or request-level effect, and the path mapping for in-repository callers is in developers' guide.