QuavernQuavsit

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.

CityNetworkDockedFree-floating
BordeauxtbmLe Vélo TBMDott, Pony, YEGO
ParisidfmVélib' MétropoleDott, Lime, YEGO
ToulousetisseoVélôToulouseYEGO
LilleileviaV'LilleLime
NicelignesdazurLime, 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#

ParameterTypeNotes
nearlat,londecimal degrees, WGS 84
radiusmetres50–5000, default 400 (/traffic: up to 100000, default 25000)
citystringBordeaux, Paris, Toulouse, Lille, Nice
networksluga Quavsit transit slug, e.g. tbm
systemidone operator in one city, e.g. dott-bordeaux
limitinteger1–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:

Meaningv1 / v2.xv3.0Quavsit
free-floating feedfree_bike_statusvehicle_statusone route
vehicle identitybike_idvehicle_idid
bikes at a stationnum_bikes_availablenum_vehicles_availablevehicles_available
a name"Quinconces"[{"text": "…", "language": "fr"}]"Quinconces"
a timestampunix secondsRFC 3339RFC 3339
a standing scooterscooterscooter_standingscooter

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.

sh
curl -sS "https://api.quavern.net/v1/mobility/stations" \
  -H "Authorization: Bearer $QUAVSIT_KEY" \
  -H "Accept: application/json"

Docked bike stations. 1 unit.

text
GET /v1/mobility/stations?near=44.8446,-0.5739&radius=300&limit=2
json
{"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.

sh
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).

text
GET /v1/mobility/vehicles?near=44.8446,-0.5739&radius=200&available_only=true&limit=2
json
{"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.

sh
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).

text
GET /v1/mobility/charging?near=44.8446,-0.5739&radius=400&min_power_kw=50&limit=2
json
{"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.

sh
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.

text
GET /v1/mobility/traffic?near=44.8446,-0.5739&radius=40000&limit=2
json
{"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.

sh
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.

text
GET /v1/mobility/systems?city=Bordeaux
json
{"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.