Navvo
Getting Started

Errors & status codes

HTTP status codes, error response shapes, and the engine availability envelope.

Errors & status codes

Navvo uses conventional HTTP status codes and a consistent error body.

Status codes

CodeMeaning
200 OKSuccessful GET.
201 CreatedSuccessful POST (NestJS returns 201 for POST handlers, even when nothing is persisted — e.g. routing).
400 Bad RequestInvalid or missing parameters / body (validation failure).
401 UnauthorizedMissing or unknown API key.
403 Forbidden (access)Key deactivated (API key revoked) or missing the required scope (code FORBIDDEN), or used from a website or IP address it is not allowed from (code KEY_WEBSITE_NOT_ALLOWED / KEY_IP_NOT_ALLOWED, see Restricting a key). Retrying won't help: fix the key.
403 Forbidden (quota)The key is over its per-minute or per-day quota, or the per-IP limit (code QUOTA_EXCEEDED). details gives limit, window, observed and, for a minute window, retryAfterSeconds, also sent as Retry-After. See Rate limits.
404 Not FoundRoute does not exist. (Note: some lookups return 200 with a null body instead — see below.)
429 Too Many RequestsYour IP address sent too many requests to one endpoint (code RATE_LIMITED). Wait for the seconds in the Retry-After header, then retry.
502 / 503A Navvo dependency (tiles, imagery) is unavailable.

An unlimited key never receives QUOTA_EXCEEDED.

Error body

Errors use the standard NestJS exception shape:

{
  "statusCode": 403,
  "message": "API key missing required scopes: routing",
  "error": "Forbidden"
}

Validation errors (400) may return message as an array of field-level messages:

{
  "statusCode": 400,
  "message": ["email must be an email", "password must be longer than or equal to 10 characters"],
  "error": "Bad Request"
}

Two behaviors worth knowing

1. The "available" envelope (engine endpoints)

Endpoints backed by a Navvo engine — Geocoding, Routing, and parts of Traffic — do not return a 5xx when the engine is unreachable. Instead they return a normal 200/201 with an available: false (or ok: false) flag and echo your request back:

{
  "provider": "navvo",
  "available": false,
  "path": "route",
  "request": { "locations": [ { "lat": 31.95, "lon": 35.91 } ], "costing": "auto" }
}
Always check the available / ok boolean on engine responses before reading data. A 200 does not guarantee a usable result.

2. "Not found" can be 200 null

A few lookup endpoints (notably GET /places/{slug}) return HTTP 200 with a null body when the resource doesn't exist, rather than a 404. Treat an empty/null body as "not found".

Handling errors

const res = await fetch("https://navvo.io/api/v1/search?q=cafe", {
  headers: { "x-api-key": key },
});

if (res.status === 429) {
  // Throttled — wait for Retry-After (seconds) before sending to this endpoint again.
  const waitSeconds = Number(res.headers.get("retry-after")) || 1;
  throw new Error(`Rate limited; retry in ${waitSeconds}s`);
}

if (res.status === 401 || res.status === 403) {
  // Auth/scope/quota problem — branch on err.code (e.g. QUOTA_EXCEEDED), don't retry blindly.
  const err = await res.json();
  throw new Error(`${err.statusCode} ${err.code}: ${err.message}`);
}

if (!res.ok) {
  // 400/5xx
  throw new Error(`Request failed: ${res.status}`);
}

const data = await res.json();
Copyright © 2026