Sports & Fitness — entry 004 of 33
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 liveGET /networks/{id}this run (e.g.citi-bike-nyc) wrapped its single result undernetwork(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-networkthis run returned HTTP 404 withcontent-type: text/plain; charset=utf-8and a bareNot Foundbody — not{}or any JSON shape, so code that always calls.json()on the response needs a try/catch here. - Per-station data under
extracarries two unrelated shapes depending on the source feed: a liveGET /networks/citi-bike-nycthis run returned GBFS-backed stations withrenting/returning/ebikes/rental_uris, while a liveGET /networks/alba(a smaller, Bicincittà-sourced network) returned a crowdstatusstring (e.g."offline") plus a 1-5score/reviewspair instead — onlyfree_bikes/empty_slots/timestampare 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.