Navvo
Getting Started

Authentication

How to obtain and use Navvo API keys, and what scopes control access.

Authentication

Every request to the Navvo integration API is authenticated with an API key. Keys are scoped, rate-limited, and tied to a project inside your organization.

Sending your key

Pass the key on every request using the x-api-key header:

curl "https://navvo.io/api/v1/search?q=pharmacy" \
  -H "x-api-key: nvvo_YOUR_KEY"

For URLs that a browser fetches directly and cannot add headers to — most importantly map tiles and styles in Navvo Maps — pass the key as a query parameter instead. Both api_key and apiKey are accepted:

https://navvo.io/api/v1/tiles/style?style=standard&api_key=nvvo_YOUR_KEY
Treat the query-parameter form as a convenience for map clients only. Anywhere you control the request headers, prefer x-api-key so your key doesn't end up in logs or browser history.

Key format

Navvo keys are prefixed and easy to recognize:

nvvo_<48 hex characters>

Only a hash of the key is stored server-side, together with the last four characters (for display). The plaintext is returned exactly once, when the key is created.

Scopes

Each key carries a set of scopes. A request to a scoped endpoint succeeds only if the key grants that scope. There are eleven scopes:

ScopeGrants access toEnabled by default?
searchSearch
geocodeGeocoding (incl. batch)
placesPlaces — details, hours, photos, reviews, categories, quests
routingRouting, matrix, isochrone, commute & itinerary
trafficTraffic & Incidents
telemetryTelemetry
tilesMap Tiles & Map Data
imageryImagery
geoGeofencing & addressing / Plus Codes❌ (opt-in)
insightsNavvo Insights privacy-safe aggregates❌ (opt-in)
optimizeRoute Optimization (OR-Tools)❌ (opt-in)

New keys are created with eight of the eleven scopes enabled by default. The geo, insights, and optimize scopes are off by default — request them explicitly if your integration needs geofencing, analytics, or optimization.

The live, authoritative list is also available to signed-in developers at GET /developer/scopes (each scope with a label and description).

The traffic-aware POST /traffic/route endpoint requires both the routing and traffic scopes.

Obtaining a key

The fastest way to get a key is the Developer Portal at navvo.io/developer — a point-and-click console for organizations, projects, keys, live usage and a request sandbox. Everything below is also available as a REST API if you prefer to automate it.

API keys are created through the developer portal endpoints, which are protected by a user session token (a JWT, not an API key). The flow is: account → organization → project → key. Every organization, project and key is scoped to the user who created it — you only ever see and manage your own.

1. Create an account / sign in

curl -X POST "https://navvo.io/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "name": "Your Name",
    "password": "a-strong-password-min-10-chars"
  }'

Both return an accessToken (a Bearer JWT) plus your user and session:

{
  "user": { "id": "uuid", "email": "you@example.com", "name": "Your Name", "roles": ["user"] },
  "sessionId": "uuid",
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Send this token as Authorization: Bearer <accessToken> on all /developer/* and /auth/me requests.

Minting keys requires the developer role (or admin/super_admin). A freshly registered account has only the user role — contact Navvo to have the developer role granted to your account.

2. Create an organization

curl -X POST "https://navvo.io/api/v1/developer/organizations" \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme Logistics", "slug": "acme-logistics" }'

3. Create a project

curl -X POST "https://navvo.io/api/v1/developer/organizations/<orgId>/projects" \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Driver App" }'

4. Create an API key

curl -X POST "https://navvo.io/api/v1/developer/api-keys" \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "<projectId>",
    "label": "Driver App – production",
    "plan": "startup",
    "scopes": { "geo": true }
  }'

The response contains your key in the key field — this is the only time it is shown:

{
  "key": "nvvo_3f9c2a1e8b7d6c5f4a3e2d1c0b9a8f7e6d5c4b3a2f1e0d9c8b",
  "id": "uuid",
  "label": "Driver App – production",
  "lastFour": "9c8b",
  "scopes": {
    "search": true, "geocode": true, "places": true, "routing": true,
    "traffic": true, "telemetry": true, "tiles": true, "imagery": true, "geo": true
  },
  "plan": "startup",
  "quotaPerMinute": 180,
  "quotaPerDay": 2500,
  "active": true
}

Request body — POST /developer/api-keys

projectId
string required
The project this key belongs to.
label
string required
Human-readable name for the key (shown in listings).
plan
string
One of free, startup, growth, enterprise. Defaults to free.
scopes
object
A { scope: boolean } map merged over the defaults. Pass { "geo": true } to enable the opt-in scope, or { "telemetry": false } to disable one.
quotaPerMinute
number
Per-key request ceiling per minute. Defaults to 180.
quotaPerDay
number
Per-key request ceiling per day. Defaults to 2500.

Managing keys

All of these endpoints require your Authorization: Bearer <accessToken> session token and are scoped to your account.

MethodPathPurpose
GET/developer/overviewCatalog of products, plans, and rate limits.
GET/developer/scopesThe authoritative scope catalog (label, description, defaults).
GET/developer/summaryYour counts (organizations, projects, keys, active keys) and requests today.
GET/developer/organizationsList your organizations.
POST/developer/organizationsCreate an organization (body: name; slug optional, auto-generated).
PATCH/developer/organizations/:idRename an organization.
DELETE/developer/organizations/:idDelete an organization (cascades to its projects and keys).
GET/developer/projects?organizationId=…List projects.
POST/developer/organizations/:id/projectsCreate a project under an organization (body: name).
POST/developer/projectsCreate a project (flat form — body: name, organizationId).
PATCH/developer/projects/:idRename a project.
DELETE/developer/projects/:idDelete a project (cascades to its keys).
GET/developer/api-keys?projectId=…List keys. Shows lastFour, scopes, plan, quotas, active, and live usage — never the plaintext.
POST/developer/api-keysMint a key (see Obtaining a key). Returns the plaintext once.
GET/developer/api-keys/:id/usageLive per-key usage: requests this minute / today vs. quota.
PATCH/developer/api-keys/:idUpdate a key's label, plan, scopes, quotaPerMinute, quotaPerDay, or active. Scope changes are merged over the key's current scopes.
POST/developer/api-keys/:id/rotateGenerate a new secret and invalidate the old one. Returns the new plaintext once.
DELETE/developer/api-keys/:idPermanently delete a key.
POST/developer/sandboxRun a read-only test request as one of your keys, server-side (body: apiKeyId, path, method? GET|POST, body?). Powers the portal Sandbox.

Disabling vs. deleting

To temporarily turn a key off (and back on), set active:

curl -X PATCH "https://navvo.io/api/v1/developer/api-keys/<keyId>" \
  -H "Authorization: Bearer <accessToken>" \
  -H "Content-Type: application/json" \
  -d '{ "active": false }'

An inactive key is rejected with 403 Forbidden until you re-enable it. DELETE removes the key permanently.

Rotating a key

If a key is leaked or lost, rotate it — this mints a brand-new secret and immediately invalidates the previous one, keeping the same key id, scopes and quotas:

curl -X POST "https://navvo.io/api/v1/developer/api-keys/<keyId>/rotate" \
  -H "Authorization: Bearer <accessToken>"

The response includes the new key in plaintext — again, shown only once. Deploy the new secret to your apps; the old one stops working immediately.

Prefer a zero-downtime rotation? Mint a second key, deploy it everywhere, confirm traffic has moved over, then delete (or deactivate) the original.

Errors

StatusMeaning
401 UnauthorizedNo key supplied where one is required, or the key you sent is unknown or revoked.
403 ForbiddenKey missing the required scope, or a quota/rate limit was exceeded.
A presented key is always validated. If you send an API key (header or query parameter), it must be a real, active key — an unknown, rotated-away, or deactivated key returns 401 on every endpoint. Rotating or deactivating a key from the developer portal therefore takes effect immediately.

See Errors for response bodies and Rate limits for quota details.

Copyright © 2026