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 ForbiddenKey revoked, missing the required scope, or a rate limit was exceeded.
404 Not FoundRoute does not exist. (Note: some lookups return 200 with a null body instead — see below.)
502 / 503A Navvo dependency (tiles, imagery) is unavailable.

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 Trafficdo 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 === 401 || res.status === 403) {
  // Auth/scope/quota problem — inspect message, don't retry blindly.
  const err = await res.json();
  throw new Error(`${err.statusCode}: ${err.message}`);
}

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

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