QuavernQuavsit

Section 01 of 12

Getting started

Quavsit is a read-only HTTP API for French public transport: lines, stops, next departures, vehicle positions, service alerts, places and journeys, for several networks behind one data model. Every answer says whether it is realtime or scheduled. This page takes you from a key to a first answer in a few minutes.

Base URL#

All endpoints live under https://api.quavern.net/v1. Requests are plain GET calls with query parameters; responses are JSON, UTF-8, gzip-compressed when the client accepts it. There are no write endpoints.

Create a key#

Keys are created on your myQuavern account at my.quavern.com/account/quavsit. A key starts with qv_p_, is shown once, stored hashed, and can be revoked from the same page. The Free plan needs no payment method and includes 5 000 units per month; see Limits and pricing.

Your account email must be verified before a key is accepted by the API.

First request#

Replace qv_p_… with your key. The example lists the networks the API knows about; it costs one unit.

sh
curl -sS "https://api.quavern.net/v1/networks" \
  -H "Authorization: Bearer qv_p_…"

Then the next departures at a stop (ids below are illustrative; find real ones with /places or /networks/{network}/stops):

sh
curl -sS "https://api.quavern.net/v1/stops/tbm:stop:3824/departures?limit=5" \
  -H "Authorization: Bearer qv_p_…"

Python#

The standard library is enough; no SDK is required.

python
import json
import urllib.parse
import urllib.request

BASE = "https://api.quavern.net/v1"
KEY = "qv_p_…"

def get(path, **params):
    query = urllib.parse.urlencode(params)
    url = f"{BASE}{path}" + (f"?{query}" if query else "")
    request = urllib.request.Request(url, headers={"Authorization": f"Bearer {KEY}"})
    with urllib.request.urlopen(request, timeout=15) as response:
        return json.load(response)

payload = get("/stops/tbm:stop:3824/departures", limit=5)
for departure in payload["data"]:
    print(departure["line_code"], departure["headsign"], departure["expected_at"] or departure["scheduled_at"])

JavaScript#

Works in Node 18+ and in server-side runtimes. Do not ship a key to browsers; call the API from your own backend.

js
const BASE = "https://api.quavern.net/v1";
const KEY = "qv_p_…";

async function get(path, params = {}) {
  const url = new URL(BASE + path);
  for (const [name, value] of Object.entries(params)) url.searchParams.set(name, String(value));
  const response = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` } });
  const body = await response.json();
  if (!response.ok) throw new Error(`${body.error.code} ${body.error.reason}`);
  return body;
}

const { data, meta } = await get("/stops/tbm:stop:3824/departures", { limit: 5 });
console.log(meta.freshness, data.map((d) => `${d.line_code} ${d.headsign}`));

Read the response#

Every success is {"data": …, "meta": {…}}. meta.freshness tells you whether at least one item is realtime; meta.attribution carries the operator credit you must display; the X-Quavsit-Units and X-Quavsit-Units-Remaining headers report what the call cost and what is left this month. Errors are {"error": {"code", "reason", "message"}} with a stable reason slug. Details in Concepts and Errors.

Next steps#

Read Authentication for scopes and what is not accepted, Networks for what each operator publishes, and Endpoints for the full route list with parameters. The web app at quavsit.quavern.com uses the same API and is a convenient way to find ids.