Section 05 sur 12
Endpoints
URL de base https://api.quavern.net/v1. Toutes les routes sont en GET. Les exemples JSON sont illustratifs : identifiants, noms et heures sont plausibles, pas des données réelles. Chaque route coûte 1 unité sauf mention contraire.
Paramètres communs#
| Paramètre | Type | Notes |
|---|---|---|
limit | entier | 1–100, 20 par défaut (passages : 1–50, 10 par défaut ; lieux : ≤ 20 ; itinéraires : ≤ 6) |
cursor | chaîne | opaque, issu de meta.next_cursor |
network / networks | slug / liste séparée par des virgules | restreint les endpoints multi-réseaux |
near | lat,lon | degrés décimaux, WGS 84 |
radius | mètres | 50–5000, 500 par défaut |
bbox | min_lon,min_lat,max_lon,max_lat | au plus 0,5° × 0,5° |
modes | liste | tram,bus,… |
q | chaîne | 1–120 caractères, recherche par préfixe sur les noms |
when | RFC 3339 ou now | now par défaut |
horizon | minutes | 5–180, 60 par défaut |
include | liste | extensions, selon la route |
lang | chaîne | accepté et ignoré ; les données sont dans la langue de l'opérateur |
Une valeur invalide renvoie 400 transit_query_invalid ou 400 invalid_location.
Santé et état#
GET /health#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/health" \
-H "Accept: application/json"Public, non comptabilisé. {"status": "ok", "service": "quavsit-api"}.
GET /status#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/status" \
-H "Accept: application/json"Public, non comptabilisé, en cache 30 s. Une entrée par réseau avec l'heure du dernier import théorique, l'état du temps réel (ok, degraded, down), les budgets quotidiens amont et la dernière erreur.
{"data": [
{"network": "idfm", "static_refreshed_at": "2026-09-07T03:40:10+02:00", "realtime": "ok",
"budgets": {"idfm_siri_sm": {"used": 412, "limit": 1000, "resets_at": "2026-09-08T00:00:00+02:00"}},
"last_error": null}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 0}}Réseaux#
GET /networks#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/networks" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Liste d'objets Network (forme complète dans Réseaux). Sans paramètre.
{"data": [
{"id": "tbm", "name": "TBM · Bordeaux Métropole", "city": "Bordeaux", "timezone": "Europe/Paris",
"modes": ["tram", "bus", "ferry"], "capabilities": {"realtime_departures": true, "vehicles": "gps",
"alerts": true, "journeys": "quavsit", "shapes": true, "places": true, "streams": true},
"static_refreshed_at": "2026-09-07T03:12:44+02:00"}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 8}}GET /networks/{network}#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/networks/tbm" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Le Network plus stats.
{"data": {"id": "star", "name": "STAR", "city": "Rennes", "timezone": "Europe/Paris",
"stats": {"lines": 167, "stops": 1832, "areas": 940, "shapes": 590}},
"meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "star", "freshness": "scheduled",
"attribution": ["Rennes Métropole / Keolis Rennes (STAR) — ODbL"]}}GET /networks/{network}/lines#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/networks/tbm/lines" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Liste de Line (directions sans arrêts). Paramètres : modes, q. Tri par sort_order, puis par code en ordre naturel (1, 2, 10).
{"data": [
{"id": "tbm:line:59", "network": "tbm", "code": "59", "name": "Gare Saint-Jean – Ambarès", "mode": "bus",
"color": "#8A2E8A", "text_color": "#FFFFFF", "operator": "Keolis Bordeaux Métropole", "sort_order": 59, "accessible": true,
"directions": [{"id": "0", "name": "Ambarès", "headsign": "Ambarès Centre"}, {"id": "1", "name": "Gare Saint-Jean", "headsign": "Gare Saint-Jean"}]}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 1, "limit": 20, "next_cursor": null}}Lignes#
GET /lines/{line_id}#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/lines/tbm:line:59" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Une Line avec directions[].stops (identifiants d'arrêts ordonnés). include=geometry ajoute shapes (GeoJSON LineString ou MultiLineString par direction).
{"data": {"id": "idfm:line:C01371", "network": "idfm", "code": "1", "name": "Métro 1", "mode": "metro",
"color": "#FFCD00", "text_color": "#000000",
"directions": [{"id": "0", "name": "La Défense", "headsign": "La Défense", "stops": ["idfm:stop:31481", "idfm:stop:31482"]}],
"shapes": [{"line_id": "idfm:line:C01371", "direction_id": "0", "geometry": {"type": "LineString", "coordinates": [[2.4, 48.85], [2.39, 48.85]]}}]},
"meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "idfm", "freshness": "scheduled"}}GET /lines/{line_id}/stops#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/lines/tbm:line:59/stops" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Arrêts ordonnés par direction : [{direction_id, stops: [Stop]}].
{"data": [
{"direction_id": "0", "stops": [
{"id": "tbm:stop:3824", "network": "tbm", "kind": "stop", "name": "Quinconces", "lat": 44.8437, "lon": -0.5742,
"parent_id": "tbm:area:BEPIS66", "line_ids": ["tbm:line:B", "tbm:line:C"], "modes": ["tram"], "town": "Bordeaux",
"accessible": true, "platform_code": "A", "children": []}
]}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "tbm"}}GET /lines/{line_id}/vehicles#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/lines/tbm:line:59/vehicles" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Liste des Vehicle en circulation sur la ligne. 404 capability_unsupported quand le réseau n'a pas de véhicules (idfm, sncf, ilevia, métro STAR).
{"data": [
{"id": "tam:vehicle:2087", "network": "tam", "line_id": "tam:line:1", "direction_id": "1", "headsign": "Odysseum",
"lat": 43.6087, "lon": 3.8797, "bearing": 112.0, "speed_kmh": 24.5, "delay_seconds": 40, "status": "in_transit",
"current_stop_id": null, "next_stop_id": "tam:stop:1204", "trip_id": "tam:trip:11-4-A-2", "position_source": "gps",
"recorded_at": "2026-09-07T14:10:51+02:00", "occupancy": null}
], "meta": {"generated_at": "2026-09-07T12:10:55Z", "units": 1, "network": "tam", "freshness": "realtime"}}GET /lines/{line_id}/alerts#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/lines/tbm:line:59/alerts" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Perturbations actives maintenant (ou à when) sur la ligne.
{"data": [
{"id": "tisseo:alert:8123", "network": "tisseo", "severity": "warning", "title": "Travaux ligne A",
"message": "Trafic interrompu entre Jean-Jaurès et Marengo à partir de 21 h.", "cause": "construction", "effect": "reduced_service",
"line_ids": ["tisseo:line:11821949021891696"], "stop_ids": [], "starts_at": "2026-09-07T21:00:00+02:00",
"ends_at": "2026-09-08T05:00:00+02:00", "updated_at": "2026-09-06T16:02:00+02:00", "url": null, "source": "tisseo:messages"}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "tisseo", "count": 1}}Arrêts#
GET /networks/{network}/stops#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/networks/tbm/stops" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Recherche ou liste d'arrêts. Paramètres : q (préfixe, insensible aux accents), near + radius, bbox, line (identifiant de ligne), kind (stop ou area), limit, cursor. Tri par pertinence avec q, par distance avec near.
{"data": [
{"id": "idfm:area:71264", "network": "idfm", "kind": "area", "name": "Châtelet", "lat": 48.8584, "lon": 2.3470,
"parent_id": null, "line_ids": ["idfm:line:C01371", "idfm:line:C01374"], "modes": ["metro", "rail"], "town": "Paris",
"accessible": false, "platform_code": null, "children": ["idfm:stop:31481", "idfm:stop:31482"]}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 1, "limit": 20, "next_cursor": null}}GET /stops/{stop_id}#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/stops/tbm:stop:3824" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Un Stop avec lines (objets Line compacts).
{"data": {"id": "tisseo:area:SA_1715", "network": "tisseo", "kind": "area", "name": "Jean Jaurès", "lat": 43.6055, "lon": 1.4490,
"children": ["tisseo:stop:SP_1012"], "lines": [{"id": "tisseo:line:11821949021891696", "code": "A", "name": "Métro A", "mode": "metro", "color": "#E4032E"}]},
"meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "tisseo"}}GET /stops/{stop_id}/alerts#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/stops/tbm:stop:3824/alerts" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Perturbations touchant l'arrêt (ou l'un des enfants d'une zone). Même forme que les perturbations de ligne.
{"data": [], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "sncf", "count": 0}}Passages#
GET /stops/{stop_id}/departures#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/stops/tbm:stop:3824/departures?limit=5" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Prochains passages triés par expected_at, à défaut scheduled_at. Paramètres : limit (1–50, 10 par défaut), line, direction, horizon, when. Un identifiant de zone agrège ses enfants.
{"data": [
{"stop_id": "tbm:stop:3824", "line_id": "tbm:line:B", "line_code": "B", "line_name": "Tram B", "mode": "tram",
"color": "#E3007D", "text_color": "#FFFFFF", "direction_id": "0", "headsign": "Berges de la Garonne",
"scheduled_at": "2026-09-07T14:12:00+02:00", "expected_at": "2026-09-07T14:13:20+02:00", "delay_seconds": 80,
"realtime": true, "status": "delayed", "trip_id": "tbm:trip:B-14-0-118", "vehicle_id": "tbm:vehicle:2311",
"platform": "A", "source": "tbm:xtradata:horai"},
{"stop_id": "tbm:stop:3824", "line_id": "tbm:line:B", "line_code": "B", "line_name": "Tram B", "mode": "tram",
"color": "#E3007D", "text_color": "#FFFFFF", "direction_id": "0", "headsign": "Berges de la Garonne",
"scheduled_at": "2026-09-07T14:20:00+02:00", "expected_at": null, "delay_seconds": null,
"realtime": false, "status": "unknown", "trip_id": "tbm:trip:B-14-0-119", "vehicle_id": null, "platform": "A", "source": "gtfs"}
], "meta": {"generated_at": "2026-09-07T12:11:03Z", "units": 1, "network": "tbm", "freshness": "realtime",
"sources": [{"id": "tbm:xtradata:horai", "fetched_at": "2026-09-07T12:10:58Z", "age_seconds": 5, "freshness": "realtime"}],
"attribution": ["Bordeaux Métropole / TBM — Licence Ouverte 2.0"], "count": 2, "limit": 10}}GET /stops/{stop_id}/departures/stream#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS -N "https://api.quavern.net/v1/stops/tbm:stop:3824/departures/stream?interval=20" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: text/event-stream"Server-sent events avec le même data que ci-dessus, poussé toutes les interval secondes. Voir Streams.
GET /lines/{line_id}/vehicles/stream#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS -N "https://api.quavern.net/v1/lines/tbm:line:59/vehicles/stream?interval=10" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: text/event-stream"Server-sent events avec les véhicules d'une ligne. Voir Streams.
À proximité#
GET /stops/nearby#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/stops/nearby?near=44.8378%2C-0.5792&radius=500" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Arrêts autour d'un point, tous réseaux confondus : chaque Stop gagne distance_meters. Paramètres : near (obligatoire), radius, networks, modes, limit.
{"data": [
{"id": "star:area:1234", "network": "star", "kind": "area", "name": "République", "lat": 48.1103, "lon": -1.6790,
"modes": ["metro", "bus"], "distance_meters": 84}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 1, "limit": 20}}GET /departures/nearby#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/departures/nearby?near=44.8378%2C-0.5792&radius=500" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Passages fusionnés autour d'un point : [{stop, distance_meters, departures}]. Paramètres : near (obligatoire), radius (≤ 1500), networks, modes, horizon (≤ 90), limit (arrêts, ≤ 10).
{"data": [
{"stop": {"id": "star:area:1234", "network": "star", "kind": "area", "name": "République", "lat": 48.1103, "lon": -1.6790},
"distance_meters": 84,
"departures": [{"stop_id": "star:stop:1234-1", "line_id": "star:line:0006", "line_code": "C6", "mode": "bus", "headsign": "Rigourdière",
"scheduled_at": "2026-09-07T14:15:00+02:00", "expected_at": "2026-09-07T14:15:40+02:00", "delay_seconds": 40, "realtime": true, "status": "delayed", "source": "star:ods:passages"}]}
], "meta": {"generated_at": "2026-09-07T12:11:03Z", "units": 1, "freshness": "realtime", "count": 1}}GET /vehicles/nearby#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/vehicles/nearby?near=44.8378%2C-0.5792&radius=1500" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Véhicules en circulation dans radius (≤ 5000) sur les réseaux qui publient ou estiment des positions. Paramètres : near (obligatoire), radius, networks, modes, limit.
{"data": [
{"id": "rla:vehicle:512", "network": "rla", "line_id": "rla:line:T1", "direction_id": "0", "headsign": "Hôpital Pasteur",
"lat": 43.7031, "lon": 7.2661, "bearing": 45.0, "speed_kmh": 18.0, "status": "in_transit", "position_source": "gps",
"recorded_at": "2026-09-07T14:10:40+02:00"}
], "meta": {"generated_at": "2026-09-07T12:10:45Z", "units": 1, "freshness": "realtime", "count": 1}}Perturbations#
GET /networks/{network}/alerts#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/networks/tbm/alerts" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Perturbations actives d'un réseau. Paramètres : severity, line, when, limit, cursor.
{"data": [
{"id": "sncf:alert:c9a1", "network": "sncf", "severity": "critical", "title": "Train supprimé",
"message": "TER 866412 Bordeaux – Arcachon est supprimé.", "line_ids": ["sncf:line:SNCF:FR:Line::9f472c56-1a2b-4c3d-9e8f-000000000000:"],
"stop_ids": ["sncf:area:87581009"], "starts_at": "2026-09-07T06:00:00+02:00", "ends_at": "2026-09-07T23:59:00+02:00",
"updated_at": "2026-09-07T07:12:00+02:00", "url": null, "source": "sncf:navitia:disruptions"}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "network": "sncf", "count": 1, "limit": 20, "next_cursor": null}}GET /alerts#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/alerts?networks=tbm%2Ctisseo" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Perturbations sur plusieurs réseaux. networks est obligatoire ; autres paramètres comme ci-dessus.
{"data": [], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 0, "limit": 20, "next_cursor": null}}Lieux#
GET /places#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/places?q=quinconces" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Recherche unifiée sur les arrêts et zones (base Quavsit) et les adresses (BAN). Paramètres : q (obligatoire), near (biais), networks, providers (stops, addresses ; les deux par défaut), limit (≤ 20). Voir Lieux.
{"data": [
{"id": "tbm:area:BEPIS66", "kind": "area", "name": "Quinconces", "label": "Quinconces, Bordeaux", "lat": 44.8437, "lon": -0.5742,
"network": "tbm", "stop_id": "tbm:area:BEPIS66", "town": "Bordeaux", "postcode": null, "source": "store", "score": 0.98},
{"id": "ban:33063_6120_00012", "kind": "address", "name": "12 Cours du Chapeau Rouge", "label": "12 Cours du Chapeau Rouge 33000 Bordeaux",
"lat": 44.8412, "lon": -0.5716, "network": null, "stop_id": null, "town": "Bordeaux", "postcode": "33000", "source": "ban", "score": 0.71}
], "meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1, "count": 2, "limit": 10}}GET /places/reverse#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/places/reverse?near=44.8378%2C-0.5792" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"near obligatoire. Adresse la plus proche (BAN) et arrêts les plus proches.
{"data": {"address": {"id": "ban:33063_6120_00012", "kind": "address", "label": "12 Cours du Chapeau Rouge 33000 Bordeaux", "lat": 44.8412, "lon": -0.5716, "source": "ban"},
"stops": [{"id": "tbm:area:BEPIS66", "kind": "area", "name": "Quinconces", "lat": 44.8437, "lon": -0.5742, "network": "tbm", "distance_meters": 310}]},
"meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 1}}Itinéraires#
GET /journeys#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/journeys?from=tbm%3Astop%3A3824&to=tbm%3Aarea%3ABEPIS66" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Itinéraires entre deux points d'un même réseau. Coûte 5 unités. Paramètres : from, to (identifiant d'arrêt, lat,lon ou texte libre), when, arrive_by, modes, planner (auto, native, quavsit), max_walk (mètres, 1000 par défaut, ≤ 2500), network, limit (≤ 6). Les règles et la forme des Section sont dans Itinéraires.
{"data": [
{"id": "j_7f3a", "departure_at": "2026-09-07T14:15:00+02:00", "arrival_at": "2026-09-07T14:41:00+02:00", "duration_seconds": 1560,
"transfers": 1, "walking_seconds": 420, "walking_meters": 510, "fare": {"amount": 210, "currency": "EUR", "text": "2,10 €"}, "co2_grams": 62.0,
"source": "idfm", "realtime": true,
"sections": [
{"kind": "walk", "departure_at": "2026-09-07T14:15:00+02:00", "arrival_at": "2026-09-07T14:19:00+02:00", "duration_seconds": 240, "distance_meters": 290,
"from_place": {"kind": "address", "label": "10 Rue de Rivoli 75004 Paris", "lat": 48.8556, "lon": 2.3592}, "to_place": {"kind": "area", "stop_id": "idfm:area:71264", "name": "Châtelet", "lat": 48.8584, "lon": 2.3470}, "realtime": false},
{"kind": "transit", "departure_at": "2026-09-07T14:21:00+02:00", "arrival_at": "2026-09-07T14:35:00+02:00", "duration_seconds": 840,
"line": {"id": "idfm:line:C01371", "code": "1", "name": "Métro 1", "mode": "metro", "color": "#FFCD00", "text_color": "#000000"}, "headsign": "La Défense", "direction_id": "0",
"stop_ids": ["idfm:stop:31481", "idfm:stop:31490"], "realtime": true}
]}
], "meta": {"generated_at": "2026-09-07T12:11:03Z", "units": 5, "network": "idfm", "freshness": "realtime", "count": 1, "limit": 3}}Usage#
GET /usage#
Essayer
Remplacez la clé et les identifiants ; l’URL de base est celle de l’API de ce site.
curl -sS "https://api.quavern.net/v1/usage" \
-H "Authorization: Bearer $QUAVSIT_KEY" \
-H "Accept: application/json"Plan de l'appelant, période, unités consommées et restantes, état du dépassement, dépense, et chiffres par clé. Coûte 0 unité.
{"data": {"plan": "starter", "period": "2026-09", "included_units": 50000, "units": 12840, "remaining": 37160,
"overage_available": true, "overage_enabled": false, "overage_unit_amount_decimal": "0.02",
"billable_units": 0, "spent_cents": 0, "spend_cap_cents": 2000, "resets_at": "2026-10-01T00:00:00+00:00",
"keys": [{"id": "3f0c…", "name": "Quavsit key", "prefix": "qv_p_3f0c", "last_four": "9k2Q", "units_today": 412, "units_period": 12840, "last_used_at": "2026-09-07T11:58:41+00:00"}]},
"meta": {"generated_at": "2026-09-07T12:00:00Z", "units": 0}}