Sports & Fitness — entry 005 of 34
City Bikes
City Bikes (CityBik.es) aggregates real-time bike-share data for 700+ networks worldwide into one JSON API, covering station locations, available bikes and e-bikes, free docks, and GBFS feed links where a network publishes one. It's free and keyless -- the only condition is crediting the CityBikes project and linking back to it from any app built on the data.
City Bikes is a two-step, keyless JSON API: `GET /networks` returns a flat index of every bike-share network it tracks (800 of them, live-counted this run), and a `fields=` projection trims that index down before you ever have to fetch a single network's full station list from `GET /networks/{id}`. A live GET this run confirmed the projected index answers in 110,890 bytes versus 225,876 bytes unprojected -- roughly half the payload for the same 800 entries.
GreatAPIs Score
Auth quickstart
- No API key, signup, or credit card required. A live GET this run confirmed the index endpoint answers keyless with a `ratelimit-limit: 300` (per hour) header pair that counts down on every call, including 404s -- there's no token to raise it. The project's own docs ask that anything built on the data credit CityBikes and link back to it, but that's a courtesy request, not something the API enforces.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
List bike-share networks (fields projection)
GEThttps://api.citybik.es/v2/networks?fields=id,name,location
{"networks":[{"id":"abu-dhabi-careem-bike","name":"Abu Dhabi Careem BIKE","location":{"latitude":24.4866,"longitude":54.3728,"city":"Abu Dhabi","country":"AE"}},{"id":"acces-velo-saguenay","name":"Accès Vélo","location":{"latitude":48.433333,"longitude":-71.083333,"city":"Saguenay","country":"CA"}},{"...":"798 more networks, same shape"}]}Try it
Developer reference
https://api.citybik.es/v2- GET/networks?fields=id,name,location
- GET/networks/{id}
- GET/networks/{id}?fields=stations
Gotchas & limits
- The index and detail routes wrap their payload under different singular/plural keys: the index above answers `{"networks":[...]}`, while a live `GET /networks/{id}` this run (e.g. `citi-bike-nyc`) wrapped its single result under `network` (singular) -- code that walks both routes needs to unwrap each envelope by its own key.
- An unknown network ID doesn't 404 with a JSON error like the rest of the host: a live `GET /networks/does-not-exist-network` this run returned HTTP 404 with `content-type: text/plain; charset=utf-8` and a bare `Not Found` body -- not `{}` or any JSON shape, so code that always calls `.json()` on the response needs a try/catch here.
- Per-station data under `extra` carries two unrelated shapes depending on the source feed: a live `GET /networks/citi-bike-nyc` this run returned GBFS-backed stations with `renting`/`returning`/`ebikes`/`rental_uris`, while a live `GET /networks/alba` (a smaller, Bicincittà-sourced network) returned a crowd `status` string (e.g. `"offline"`) plus a 1-5 `score`/`reviews` pair instead -- only `free_bikes`/`empty_slots`/`timestamp` are shared across every network.
- Rate limiting is keyless but real: every response this run carried `ratelimit-limit: 300` / `ratelimit-remaining` (per hour) headers ticking down on both 200s and 404s, confirming the 300-requests-per-hour ceiling applies with no way to raise it.