Developers · Routing API

Routing API for bikes, scooters, motorcycles and wheelchairs.

The routing engine of the « On va où ? » navigation and safety app, for your own products. One request returns up to three variants, safe, balanced and fast, billed as a single request, with what makes a two-wheel route good or bad: cycle lanes, surfaces, main roads, elevation.

Why this API

Quick start

Create an account and a key at console.onvaou.app, then send the key in the x-api-key header. Call the API from your server, never from a web page or a mobile app.

curl -X POST https://api.onvaou.app/v1/routes \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"origin":[2.3522,48.8566],"destination":[2.4392,48.8474],"mode":"bike"}'

Request: POST /v1/routes

FieldTypeDescription
origin, destination[lon, lat]Required, WGS 84.
waypoints[[lon, lat]]Up to 8 intermediate points.
modestringbike (default), ebike, scooter (kick scooter), moto (motorcycle), wheelchair, foot.
variantsstring[]Any of safe, balanced, fast. Default: all three.
avoidstring[]ferries, steps; tolls, highways (motorcycle); unpaved, steep (wheelchair).
elevationbooleanElevation profile, default true.
instructionsbooleanTurn-by-turn steps, default true.
languagestringfr (default), en, de, es, it, nl, pt.
geometrystringgeojson (default) or polyline (Google algorithm, precision 5).

Response

{
  "mode": "bike",
  "routes": [
    {
      "variants": ["safe", "balanced", "fast"],
      "distanceM": 7159,
      "durationS": 1525,
      "ascentM": 38,
      "descentM": 41,
      "indicators": { "cyclewayShare": 0.773, "unpavedShare": 0, "mainRoadShare": 0.036, "motorwayShare": 0 },
      "geometry": { "type": "LineString", "coordinates": [[2.3522, 48.8566], "..."] },
      "elevationProfile": [[0, 35], [95, 36], "..."],
      "steps": [{ "instruction": "Head east", "name": "Quai de l'Hôtel de Ville", "distanceM": 120, "durationS": 28, "type": 11 }]
    }
  ],
  "usage": { "month": "2026-09", "requests": 1, "quota": 10000, "plan": "decouverte" },
  "attribution": "© On va où ? · © openrouteservice by HeiGIT · © OpenStreetMap contributors"
}

When the engine finds a single sensible route, it is returned once with all the requested labels. Variants are never invented. Display the attribution next to the route you show.

Address search: POST /v1/geocode

An address, a place name, a station or a point of interest becomes coordinates, ready to pass as origin, destination or a waypoint of /v1/routes. Up to five candidates, best first; when nothing matches, the answer is a 200 with an empty results array.

curl -X POST https://api.onvaou.app/v1/geocode \
  -H "x-api-key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"10 rue de Rivoli, Paris","country":"FR","limit":3}'
FieldTypeDescription
querystringRequired, from 2 to 200 characters.
near{lon, lat}Proximity bias; it does not restrict the search. The point must be inside the European coverage, otherwise 422 out_of_coverage.
countrystringISO 3166-1 alpha-2 country code, uppercase (FR, BE, DE…). FR is served by the IGN Géoplateforme.
limitintegerFrom 1 to 5, 5 by default.
languagestringen (default), fr, de, it. Closed list: any other value is refused with 400 bad_language. it is accepted, but Photon does not label in Italian: labels then come back in the local language of each place (Milano, München).
{
  "query": "10 rue de Rivoli, Paris",
  "source": "geoplateforme",
  "results": [
    {
      "label": "10 Rue de Rivoli, 75004 Paris",
      "lon": 2.35704, "lat": 48.85655,
      "type": "address", "confidence": 0.96,
      "country": "France", "countryCode": "FR",
      "region": "Île-de-France", "locality": "Paris", "postalCode": "75004",
      "street": "Rue de Rivoli", "houseNumber": "10"
    }
  ],
  "attribution": "© IGN Géoplateforme, Base Adresse Nationale (Licence Ouverte 2.0)",
  "usage": { "dailyLimit": 500, "usedToday": 12, "countsTowardQuota": false }
}

Any field a source does not provide is null: a locality has neither house number nor postal code, and the shape of the answer never changes.

type is always one of these seven values and of no other: address (a house number), street, locality (town, district), region, country, venue (a named place: station, hotel, monument) or other. confidence runs from 0 to 1: it is the score returned by the Géoplateforme, rounded to three decimals, when it answers, and a value computed from the rank and the precision of the result for Photon, which returns none.

Address search is not counted against the monthly quota, which counts route calculations only. It has its own cap of 500 searches per account per day (UTC), reported in the X-Geocode-Limit and X-Geocode-Used headers and in the usage field. The per-second rate of the plan applies as everywhere else, and a search identical to another one from the last 24 hours is served from cache (X-Cache: hit).

Results come from Photon, on OpenStreetMap data, across Europe, and from the IGN Géoplateforme (Base Adresse Nationale) in France. The Géoplateforme hands the search over to Photon in three cases, and only these: it is unavailable, it returns nothing, or its best confidence is below 0.4, which is what a place name such as Tour Eiffel gets from an address database. Photon takes over only when it does find something: weak candidates beat an empty list. The source field says which one answered.

Errors

StatusCodeMeaning
400bad_*, too_longInvalid request (message explains the field). For /v1/geocode: bad_query, bad_near, bad_country, bad_limit, bad_language.
401invalid_keyMissing, unknown or revoked key.
422no_route, out_of_coverageNo route between these points for this vehicle, or a point outside Europe.
429rate_limitedPlan rate exceeded (requests per second, whole account): retry after the Retry-After header.
429quota_exceededFree plan quota reached for the month.
429geocode_daily_limitDaily address-search cap reached (500 per account); it resets at midnight UTC.
404not_foundUnknown endpoint: POST /v1/routes, POST /v1/geocode, GET /v1/status.
503engine_capacity, engine_unavailableTemporary, retry later.

Attribution

Display the text of the attribution field next to the route or the results you show. It is a condition of use of the API, free and paid plans alike.

Guides

Code examples

curl, JavaScript, Python, a MapLibre map and a Postman collection, tested against the live API: github.com/onvaou-app/routing-api-examples (MIT).

MCP server (AI assistants)

Let Claude, ChatGPT or any MCP client search an address and compute routes directly: app.onvaou/itineraires in the official MCP registry, npm package onvaou-itineraires-mcp, two read-only tools, compute_route and geocode_address.

geocode_address finds an address, compute_route computes the route and its three variants: the assistant reads, it changes nothing. Each computation counts as one request of your plan, free plan included; address searches are not counted. Bike, scooter, motorcycle, wheelchair and walking routes, anywhere in Europe.

{
  "mcpServers": {
    "onvaou-itineraires": {
      "command": "npx",
      "args": ["-y", "onvaou-itineraires-mcp"],
      "env": { "OVO_API_KEY": "YOUR_KEY" }
    }
  }
}

Pricing

Monthly subscription, no commitment, prices in euros excluding VAT. Every plan includes every feature; only volume, rate and commercial use change. One request = one route calculation returning up to three variants.

PlanPrice / monthRequests / monthRateOverage / 1,000
Découverte0 €10,0001 req/sblocked (non-commercial)
Solo19 €20,0002 req/s1.00 €
Starter59 €75,0003 req/s0.90 €
Pro169 €225,00010 req/s0.80 €
Business449 €750,00025 req/s0.65 €
Customquoteabove 750,000dedicatedcoverage outside Europe, SLA

Subscribe and manage your plan at console.onvaou.app. Card payment by Stripe.

FAQ

Is there a free plan?

Yes: 10,000 requests per month for development and non-commercial use, without a credit card.

Can I use it in a commercial app?

Yes, from the Solo plan (19 € per month). Show the attribution next to the displayed route (OpenStreetMap data).

Which area is covered?

All of Europe, on every plan. For other regions, contact us (Custom plan). Points outside the coverage return 422 out_of_coverage.

Which vehicles are supported?

Bike, e-bike, kick scooter, motorcycle, wheelchair and walking, each with its own profile.

How is the safe variant chosen?

For bikes and scooters, it is the route with the highest share of cycle lanes and the fewest main roads among the alternatives. For motorcycles, it is computed avoiding motorways.