GBFS 3.0 Feeds
GBFS 3.0 is the spec the MobilityData validator now checks against, and most new tier-1 city permits reference it explicitly. Levy Fleets publishes both feeds in parallel:
| Version | Base URL | Status |
|---|---|---|
| GBFS 2.3 (legacy) | /api/gbfs/{subaccountId}/... | Untouched. Still available for consumers that haven't migrated. |
| GBFS 3.0 | /api/gbfs/v3/{subaccountId}/... | Active. Validated against MobilityData's GBFS validator with no warnings. |
No migration required
The legacy v2 feed continues to publish at its existing URL. Existing consumers don't have to change anything; cities that require GBFS 3.0 use the new /v3/ URL.
Feed root — gbfs.json
curl https://fleets.levyelectric.com/api/gbfs/v3/<subaccountId>/gbfs.json
Returns the discovery document with paths to every other feed file:
{
"last_updated": "2026-05-18T12:00:00Z",
"ttl": 60,
"version": "3.0",
"data": {
"feeds": [
{ "name": "manifest", "url": "..." },
{ "name": "system_information", "url": "..." },
{ "name": "vehicle_types", "url": "..." },
{ "name": "vehicle_status", "url": "..." },
{ "name": "station_information", "url": "..." },
{ "name": "station_status", "url": "..." },
{ "name": "system_regions", "url": "..." },
{ "name": "system_pricing_plans", "url": "..." },
{ "name": "geofencing_zones", "url": "..." },
{ "name": "system_alerts", "url": "..." }
]
}
}
What's new vs GBFS 2.x
| GBFS 2.x | GBFS 3.0 | Why it matters |
|---|---|---|
free_bike_status.json | vehicle_status.json | Includes vehicle_type_id ref so consumers can filter by class. |
| Time fields as POSIX epoch | RFC3339 strings | Easier for humans and validators; matches MDS 2.0. |
Languages via URL prefix (/en/, /es/) | Declared per-feed in manifest.json | One feed root serves all supported languages. |
vehicle_types.json optional | Required and structured | Carries max_range_meters, return_constraint, propulsion_type. |
No system_regions.json | Required when the fleet covers multiple regions | Lets cities draw their boundary onto an existing taxonomy. |
geofencing_zones.json has flat rules | Rules can scope to vehicle_type_id | Different zones for scooters vs ebikes in the same fleet. |
station_information lacks per-class capacity | Adds vehicle_type_capacity | Mixed-fleet stations get accurate capacity numbers. |
manifest.json
New in 3.0. Declares languages, the GBFS version, and the auth scheme (if any). Levy's manifest is generated from the subaccount's default_language plus any languages with at least one localized field.
{
"last_updated": "2026-05-18T12:00:00Z",
"ttl": 60,
"version": "3.0",
"data": {
"datasets": [
{
"system_id": "levy-<subaccountId>",
"versions": [
{ "version": "3.0", "url": ".../v3/<subaccountId>/gbfs.json" },
{ "version": "2.3", "url": ".../<subaccountId>/gbfs.json" }
]
}
]
}
}
The manifest is what tells discovery aggregators (MobilityData, transit apps) that both 2.x and 3.0 are available for the same system.
vehicle_status.json
Replaces free_bike_status.json. Each row carries a vehicle_type_id that references vehicle_types.json:
{
"version": "3.0",
"last_updated": "2026-05-18T12:00:00Z",
"ttl": 60,
"data": {
"vehicles": [
{
"vehicle_id": "abc123",
"vehicle_type_id": "scooter_standard",
"lat": 40.0149,
"lon": -105.2705,
"current_range_meters": 18000,
"is_reserved": false,
"is_disabled": false,
"last_reported": "2026-05-18T11:59:47Z"
}
]
}
}
The vehicle's vehicle_type_id flows from vehicles.model_id -> vehicle_models.gbfs_type_id. Set the latter under Settings -> Vehicle Models when you import new SKUs.
geofencing_zones.json — operator + policy zones merged
This is the file where city compliance shows up in the public feed. It contains every operator zone (parking, no-parking, slow, no-go, ride zones) plus every active policy_geofences row for the subaccount. Each feature emits the right vehicle_type_id per rule per MDS Policy.
Order matters: features are sorted by priority descending so consumers that pick the "first match" get the strictest rule. See Stacked Geofence Priority.
{
"version": "3.0",
"last_updated": "2026-05-18T12:00:00Z",
"ttl": 60,
"data": {
"geofencing_zones": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Boulder Pearl Street No-Ride",
"rules": [
{
"vehicle_type_ids": ["scooter_standard"],
"ride_allowed": false,
"ride_through_allowed": false
}
],
"priority": 950,
"source": "city",
"source_jurisdiction_id": "boulder-co"
},
"geometry": { "type": "Polygon", "coordinates": [ ... ] }
}
]
}
}
}
The priority, source, and source_jurisdiction_id properties are Levy extensions on top of the GBFS schema — they're ignored by validators and consumed by clients (including our own mobile app) that understand the stack semantics.
system_regions.json
New in 3.0. Useful when a single subaccount operates across multiple distinct geographic regions (e.g., separate campuses or boroughs). Levy emits one region per mds_jurisdictions row by default; you can edit names and language labels under Compliance -> Jurisdictions -> Edit -> Regions.
system_alerts.json
Carries operator-published alerts (planned outages, special events, weather restrictions). Currently driven by the Settings -> Alerts UI; tied to subaccount, not per-jurisdiction.
Caching
Like the MDS feed, GBFS 3.0 endpoints are edge-cached for 60 seconds (Cache-Control: public, s-maxage=60). The ttl value in each file's payload matches the cache window.
Validator configuration
Use MobilityData's gbfs-validator for end-to-end checks:
gbfs-validator https://fleets.levyelectric.com/api/gbfs/v3/<subaccountId>/gbfs.json
A clean run reports Errors: 0, Warnings: 0. Common warnings to expect when first onboarding:
vehicle_type_idmissing on a vehicle — setvehicle_models.gbfs_type_idfor every model in your fleet.system_regions.jsonempty — add at least onemds_jurisdictionsrow, or remove the file fromgbfs.jsonif you don't operate across multiple regions.pricing_plansmissing — set at least one row inpricing_plansfor the subaccount.
How v2 and v3 stay in sync
Both feeds read from the same underlying tables (vehicles, vehicle_models, zones, policy_geofences, stations, pricing_plans). There is no separate write path for v3, so a change in the dashboard appears in both feeds at the next 60-second cache cycle.
The only file that lives only in v3 is manifest.json and system_regions.json. Removing the v3 feed (if a city only needs v2.x) is just a matter of not pointing them at the /v3/ URL.
What's next
- Policy Ingestion from Cities — where the policy geofences merged into
geofencing_zones.jsoncome from. - Stacked Geofence Priority — the priority ladder applied when zones overlap.
- MDS Provider Setup — the signed MDS endpoints that cities consume alongside GBFS.