advanced
GBFS
3
public-feed

GBFS 3.0 Feeds

The v3 GBFS feed at /api/gbfs/v3/{subaccountId}/* — what's new vs 2.x, how it coexists with the legacy feed, and the geofencing_zones.json with policy geofences merged in.

Levy Fleets TeamMay 18, 202612 min read

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:

VersionBase URLStatus
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.xGBFS 3.0Why it matters
free_bike_status.jsonvehicle_status.jsonIncludes vehicle_type_id ref so consumers can filter by class.
Time fields as POSIX epochRFC3339 stringsEasier for humans and validators; matches MDS 2.0.
Languages via URL prefix (/en/, /es/)Declared per-feed in manifest.jsonOne feed root serves all supported languages.
vehicle_types.json optionalRequired and structuredCarries max_range_meters, return_constraint, propulsion_type.
No system_regions.jsonRequired when the fleet covers multiple regionsLets cities draw their boundary onto an existing taxonomy.
geofencing_zones.json has flat rulesRules can scope to vehicle_type_idDifferent zones for scooters vs ebikes in the same fleet.
station_information lacks per-class capacityAdds vehicle_type_capacityMixed-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_id missing on a vehicle — set vehicle_models.gbfs_type_id for every model in your fleet.
  • system_regions.json empty — add at least one mds_jurisdictions row, or remove the file from gbfs.json if you don't operate across multiple regions.
  • pricing_plans missing — set at least one row in pricing_plans for 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