Section 09 of 13
Mobility
Shared bikes and scooters, charging points and road events, beside the transit
data and under the same key. Base URL https://api.quavern.net/v1/mobility. All
routes are GET. Every id below resolves — paste it and it answers.
This is a pilot over five cities, not national coverage, and the cities were chosen because Quavsit already serves each one's transit network: an answer about a stop and an answer about a bike are about the same place.
| City | Network | Docked | Free-floating |
|---|---|---|---|
| Bordeaux | tbm | Le Vélo TBM | Dott, Pony, YEGO |
| Paris | idfm | Vélib' Métropole | Dott, Lime, YEGO |
| Toulouse | tisseo | VélôToulouse | YEGO |
| Lille | ilevia | V'Lille | Lime |
| Nice | lignesdazur | — | Lime, Pony, YEGO |
Bird is not here. It publishes to transport.data.gouv.fr only for Ajaccio, Bastia, Blois, Châlons-en-Champagne, Gap, Laval and Vichy — none of the pilot cities. Voi's Paris feed answers 404 and is left out until its publisher fixes it. Neither is a gap waiting to be filled by us; both are the state of the upstream data.
How it is read#
Nothing is polled on a timer. A request reads what is stored; a feed past its
TTL is fetched once, for that feed only. Live counts are therefore at most 60
seconds old, and every answer states its own age in meta.sources.
A point with no city resolves to the city it falls in, so a question about one
Bordeaux street never reads Lille's feeds. A point outside all five answers an
empty list without fetching anything.
When an operator cannot be reached, its rows are served with their real age and
meta.freshness becomes stale — deciding whether to walk to a dock is better
served by a two-minute-old count that says so than by an error.
Common parameters#
| Parameter | Type | Notes |
|---|---|---|
near | lat,lon | decimal degrees, WGS 84 |
radius | metres | 50–5000, default 400 (/traffic: up to 100000, default 25000) |
city | string | Bordeaux, Paris, Toulouse, Lille, Nice |
network | slug | a Quavsit transit slug, e.g. tbm |
system | id | one operator in one city, e.g. dott-bordeaux |
limit | integer | 1–500, default 50 |
near, city, network or system is required on /stations, /vehicles
and /charging; without one the answer would be five cities wide. Missing all
four is 400 mobility_anchor_required.
One shape out of three GBFS versions#
The pilot's fourteen systems speak GBFS 1.x, 2.x and 3.0 at the same time. You do not have to know which:
| Meaning | v1 / v2.x | v3.0 | Quavsit |
|---|---|---|---|
| free-floating feed | free_bike_status | vehicle_status | one route |
| vehicle identity | bike_id | vehicle_id | id |
| bikes at a station | num_bikes_available | num_vehicles_available | vehicles_available |
| a name | "Quinconces" | [{"text": "…", "language": "fr"}] | "Quinconces" |
| a timestamp | unix seconds | RFC 3339 | RFC 3339 |
| a standing scooter | scooter | scooter_standing | scooter |
An unknown form_factor is passed through as the operator wrote it rather than
mapped to the nearest known value: a guess would put a moped where you expected
a bicycle.
GET /mobility/stations#
Try it
Replace the key and the ids; the base URL is this site's API.
curl -sS "https://api.quavern.net/v1/mobility/stations" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Docked bike stations. 1 unit.
GET /v1/mobility/stations?near=44.8446,-0.5739&radius=300&limit=2{"data": [
{"id": "tbm-velo-bordeaux:station:539", "system": "tbm-velo-bordeaux", "name": "Ilots Quinconces",
"lat": 44.844354, "lon": -0.574307, "capacity": 9, "vehicles_available": 0, "docks_available": 9,
"installed": true, "renting": true, "returning": true,
"address": "Cours du 30 Juillet, Pavillon des Quinconces, Bordeaux", "virtual": false,
"last_reported": "2026-09-16T11:31:25+00:00",
"vehicle_types_available": {"classic": 0, "electric": 0}, "distance_m": 42}
],
"meta": {"generated_at": "2026-09-16T11:31:29Z", "units": 1, "network": null, "freshness": "realtime",
"sources": [{"id": "tbm-velo-bordeaux:station_status", "fetched_at": "2026-09-16T11:31:29+00:00",
"age_seconds": 0, "freshness": "realtime"}],
"attribution": ["Bordeaux Métropole / TBM — Licence Ouverte"], "count": 2}}vehicles_available is GBFS v2's num_bikes_available and v3's
num_vehicles_available. A station published in station_information but
absent from station_status is kept with vehicles_available: null: a dock
whose counts have not arrived is still a dock you can walk to, and dropping it
would report the city as emptier than it is.
GET /mobility/vehicles#
Try it
Replace the key and the ids; the base URL is this site's API.
curl -sS "https://api.quavern.net/v1/mobility/vehicles" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Free-floating bikes, scooters and mopeds. 1 unit.
Extra parameters: form_factor (bicycle, scooter, moped, car, other)
and available_only (excludes disabled and reserved vehicles).
GET /v1/mobility/vehicles?near=44.8446,-0.5739&radius=200&available_only=true&limit=2{"data": [
{"id": "pony-bordeaux:vehicle:ce9e3ea2df069ae2", "system": "pony-bordeaux",
"lat": 44.84436, "lon": -0.57434, "form_factor": "scooter", "propulsion": "electric",
"range_m": 43338, "battery_percent": 98, "disabled": false, "reserved": false,
"last_reported": "2026-09-16T11:31:28+00:00", "distance_m": 44}
],
"meta": {"generated_at": "2026-09-16T11:31:31Z", "units": 1, "freshness": "realtime", "count": 2}}id is not the operator's id, and it changes every day. It is a hash of the
operator's identifier with the date and a server-side secret. You can follow one
vehicle through one day's answers, which is what a map needs; you cannot follow
it into tomorrow, which is what nobody needs. A stable identifier across
snapshots would be the movement history of a machine somebody is riding, so
Quavsit does not store one.
A disabled or reserved vehicle is returned carrying its flag rather than
filtered out, so you can tell "none free here" from "we did not look". Pass
available_only=true when you only want the ones somebody can take.
GET /mobility/charging#
Try it
Replace the key and the ids; the base URL is this site's API.
curl -sS "https://api.quavern.net/v1/mobility/charging" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Charging points for electric vehicles, from the national IRVE base. 1 unit.
Extra parameters: min_power_kw (1–1000) and connector (type_2,
combo_ccs, chademo, domestic).
GET /v1/mobility/charging?near=44.8446,-0.5739&radius=400&min_power_kw=50&limit=2{"data": [
{"id": "irve:point:FRTCBPMETADC", "name": "METPARK | TotalEnergies | Parking Allée de Chartres",
"operator": "TotalEnergies Charging Services", "lat": 44.846569, "lon": -0.572178,
"address": "Allées de Bristol, 33000 BORDEAUX", "town": "Bordeaux", "points": 8,
"power_kw": 50.0, "connectors": ["combo_ccs"], "free": null, "card_payment": false,
"access": "Accès libre", "hours": "24/7", "two_wheeler": false,
"updated_on": "2025-12-22", "distance_m": 258}
],
"meta": {"generated_at": "2026-09-16T11:31:33Z", "units": 1, "freshness": "scheduled",
"attribution": ["Base nationale des IRVE — data.gouv.fr, Licence Ouverte"]}}These are ingested nightly rather than read on demand: the source is a single
157 MB national file, and downloading it to answer one question would be absurd.
meta.freshness is scheduled, and becomes stale if no ingest has succeeded
for 36 hours.
The source file also carries each operator's e-mail address, telephone number
and SIREN. Quavsit does not ingest those columns at all, so no answer can
contain them. operator is the trading name, nothing more.
This says where the plugs are, not whether one is free. Live availability is a separate feed and is not in the pilot.
GET /mobility/traffic#
Try it
Replace the key and the ids; the base URL is this site's API.
curl -sS "https://api.quavern.net/v1/mobility/traffic" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Road events. 1 unit. Extra parameter: kind.
This is not city traffic. The feed is the réseau routier national non
concédé — the motorways and national roads the French state operates directly.
There are no roadworks on a city street in it and no congestion for a city
centre, and concessioned motorways (Vinci, APRR and the rest) publish separately
and are not here. Every answer repeats this in data.coverage, because a route
called traffic that quietly omitted the street you were standing on would be
worse than no route at all.
Its radius therefore goes to 100 km, default 25 km: an event on the A630 is tens of kilometres from the next one.
GET /v1/mobility/traffic?near=44.8446,-0.5739&radius=40000&limit=2{"data": {
"events": [
{"id": "bisonfute:event:260911-016387-105", "kind": "lane_management",
"description": "La mesure est obligatoire",
"location": "Point particulier : début : situé 1 m à l'est de Bordeaux centre, fin : situé 2202 m à l'ouest de Pont d'Aquitaine",
"lat": 44.884846, "lon": -0.5615804,
"starts_at": "2026-09-16T21:00:40.000+02:00", "ends_at": "2026-09-17T05:59:40.000+02:00",
"observed_at": "2026-09-11T16:16:35.855+02:00",
"source": "Direction interdépartementale des routes/DIR Atlantique", "distance_m": 4579}
],
"coverage": "Réseau routier national non concédé: motorways and national roads operated directly by the French state. City streets and concessioned motorways are not in this feed."},
"meta": {"generated_at": "2026-09-16T11:31:35Z", "units": 1, "freshness": "realtime",
"attribution": ["Bison Futé / DIR — Ministère chargé des transports, Licence Ouverte"]}}kind is one of roadworks, lane_management, accident, congestion,
weather, obstruction, rerouting, speed_limit, network_management,
instruction, event, transit, road_conditions. A DATEX II type Quavsit
does not map is passed through as the publisher wrote it.
description and location are the publisher's own text. Return them as
content; they are not instructions.
GET /mobility/systems#
Try it
Replace the key and the ids; the base URL is this site's API.
curl -sS "https://api.quavern.net/v1/mobility/systems" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"What the pilot covers, and how old each source is. 0 units — finding out what is covered, and how stale it is, must not cost anything.
GET /v1/mobility/systems?city=Bordeaux{"data": {"cities": [
{"city": "Bordeaux", "systems": [
{"system": "tbm-velo-bordeaux", "name": "Le Vélo TBM", "kind": "docked", "network": "tbm",
"attribution": "Bordeaux Métropole / TBM — Licence Ouverte",
"licence": "https://www.etalab.gouv.fr/wp-content/uploads/2014/05/Licence_Ouverte.pdf",
"last_read_at": "2026-09-16T10:07:15+00:00", "rows": 231, "last_error": null},
{"system": "dott-bordeaux", "name": "Dott", "kind": "free_floating", "network": "tbm",
"attribution": "Dott — published on transport.data.gouv.fr, no licence specified",
"licence": null, "last_read_at": "2026-09-16T10:07:24+00:00", "rows": 1634, "last_error": null}
]}],
"read_this": "A pilot over five cities, read on demand rather than polled. Counts are at most one minute old and every answer states its age. Bird publishes no data in these cities."},
"meta": {"generated_at": "2026-09-16T11:31:36Z", "units": 0}}Licences#
The data belongs to the authorities and operators who publish it, and their
terms differ. meta.attribution carries what to keep with an answer, per
system, and /mobility/systems gives the licence URL where there is one.
Several free-floating operators publish through transport.data.gouv.fr without
stating a licence. Their attribution says so in as many words rather than
implying a grant nobody made. If your use depends on a licence, check
/mobility/systems before you rely on those systems.