Availability Display
Show real-time bike parking availability on maps, dashboards, or mobile apps using the bike parking availability API. This guide is for any consumer of Bikeep availability data — including municipalities publishing open data portals, transit agencies integrating bike parking into journey planners, campus IT teams embedding availability in campus apps, and third-party mobility platforms. The Bikeep public endpoint returns location data with availability counts in GeoJSON format — no authentication required.
Important: The API provides data only, not a pre-built UI. You use the data to build your own display — a map marker, a dashboard widget, a mobile app screen, etc.
The Public Endpoint
curl https://services.bikeep.com/location/v1/public-areas/{public_area_id}/locations
No Authorization header needed. The public_area_id defines a geographic region (e.g., a city, campus, or venue). Public areas are typically created by Bikeep during onboarding, but partner-level integrators can also create and manage their own public areas via the API.
Response (GeoJSON — application/geo+json):
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [24.81521, 59.42776]
},
"properties": {
"code": "TLN-1234",
"label": "#1234",
"name": "#1234 Office Building A",
"address": "123 Main Street",
"tags": ["city-center", "24h"],
"parking": {
"available": 7,
"online": 10,
"total": 10
},
"renting": null
}
}
]
}
Note: The
rentingfield is a legacy artifact from the deprecated rental system. It appears only on a small number of rental locations in Estonia — most integrators will always seenullhere.
Key fields for display
| Field | Use |
|---|---|
geometry.coordinates |
[longitude, latitude] for map marker placement |
properties.parking.available |
Number of usable devices (available AND online) — the main number to show |
properties.parking.total |
Total capacity |
properties.name |
Human-readable station name |
properties.tags |
Array of public tags — use for filtering or categorization |
Example: Map Integration
Here is a minimal example using the public endpoint to place markers on a map:
Mapbox GL JS
<!DOCTYPE html>
<html>
<head>
<script src="https://api.mapbox.com/mapbox-gl-js/v3.0.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.0.0/mapbox-gl.css" rel="stylesheet">
<style> #map { width: 100%; height: 500px; } </style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v11',
center: [24.7536, 59.4370],
zoom: 12
});
fetch('https://services.bikeep.com/location/v1/public-areas/YOUR_PUBLIC_AREA_ID/locations')
.then(r => r.json())
.then(geojson => {
geojson.features.forEach(feature => {
const { name, parking } = feature.properties;
const [lng, lat] = feature.geometry.coordinates;
new mapboxgl.Marker()
.setLngLat([lng, lat])
.setPopup(new mapboxgl.Popup().setHTML(
`<strong>${name}</strong><br>${parking.available}/${parking.total} available`
))
.addTo(map);
});
});
</script>
</body>
</html>
Google Maps
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Bikeep Availability — Google Maps</title>
<style>
#map { width: 100%; height: 500px; }
</style>
</head>
<body>
<div id="map"></div>
<script>
async function initMap() {
const map = new google.maps.Map(document.getElementById('map'), {
center: { lat: 59.437, lng: 24.753 },
zoom: 12,
});
const response = await fetch(
'https://services.bikeep.com/location/v1/public-areas/YOUR_PUBLIC_AREA_ID/locations'
);
const geojson = await response.json();
geojson.features.forEach(feature => {
const { name, parking } = feature.properties;
const [lng, lat] = feature.geometry.coordinates;
const marker = new google.maps.Marker({
position: { lat, lng },
map,
title: `${name} — ${parking.available}/${parking.total}`,
});
const infoWindow = new google.maps.InfoWindow({
content: `<strong>${name}</strong><br>${parking.available}/${parking.total} available`,
});
marker.addListener('click', () => infoWindow.open(map, marker));
});
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_MAPS_API_KEY&callback=initMap" async defer></script>
</body>
</html>
Polling for Updates
The public endpoint returns the current state at the time of the request. To keep your display up-to-date, poll the endpoint periodically.
Bike parking availability changes slowly — a station might see a handful of events per hour. Polling every 5–10 minutes is a good fit for most use cases.
Recommended intervals:
- Public display / signage: Every 5–10 minutes
- Mobile app: Every 5–10 minutes, or on screen focus
- Dashboard: Every 5 minutes
// Simple polling example
setInterval(async () => {
const response = await fetch(
'https://services.bikeep.com/location/v1/public-areas/YOUR_PUBLIC_AREA_ID/locations'
);
const geojson = await response.json();
updateMarkers(geojson); // Your update function
}, 300000); // 5 minutes
Authenticated Alternative
If you need more detailed device-level data (individual device states, hardware health, booking status), use the authenticated endpoint instead:
curl https://services.bikeep.com/location/v1/locations \
-H "Authorization: Bearer {token}"
This returns richer location data with device-level detail — individual device states, hardware health, and diagnostic information. See Authentication for setup.
What Integrators Have Built
Bikeep’s public API data is used in a variety of displays:
- Campus maps — University bike parking availability embedded in campus apps
- Smart city dashboards — City-wide availability heatmaps for urban planning
- Venue apps — Stadium and arena apps showing nearby bike parking before events
- Digital signage — Screens near bike stations showing current availability
- Transit apps — Bike parking availability integrated alongside transit schedules