Map Export API for Developers: Integrating osm2cdr.ru
osm2cdr.ru provides a REST API for automating OpenStreetMap map exports. Instead of manual work through the interface — programmatic access to 127 export formats, 165 coordinate systems, 4 cartographic styles and 85 colour palettes.
Quick Start
Getting an API Key
Register on osm2cdr.ru and get your API key from the dashboard. The key is passed in the X-API-Key header.
Access and payment:
| What | Terms |
|---|---|
| API requests | Free |
| Full file of any format | Paid — per file or from the wallet |
| Demo file | Free |
| Order price | GET /api/pricing/quote or the /pricing/ page |
| Technical area limits | GET /api/format-limits |
First Request (Python)
import requests
import time
API_KEY = "your-api-key"
BASE_URL = "https://osm2cdr.ru/api"
# Step 1: Create export task
response = requests.post(f"{BASE_URL}/export", json={
"bbox": [37.60, 55.74, 37.64, 55.76], # [min_lon, min_lat, max_lon, max_lat]
"format": "geojson",
"style": "default",
"detail_level": 4
}, headers={"X-API-Key": API_KEY})
task = response.json()
task_id = task["task_id"]
print(f"Task created: {task_id}")
# Step 2: Wait for completion
while True:
status = requests.get(
f"{BASE_URL}/status/{task_id}",
headers={"X-API-Key": API_KEY}
).json()
if status["status"] == "completed":
break
elif status["status"] == "failed":
print(f"Error: {status['error']}")
break
print(f"Progress: {status.get('progress', 0)}%")
time.sleep(2)
# Step 3: Download result
download_url = status["download_url"]
result = requests.get(download_url)
with open("moscow_center.geojson", "wb") as f:
f.write(result.content)
print("Downloaded!")
First Request (JavaScript)
const API_KEY = 'your-api-key';
const BASE_URL = 'https://osm2cdr.ru/api';
async function exportMap() {
// Create task
const response = await fetch(`${BASE_URL}/export`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY
},
body: JSON.stringify({
bbox: [37.60, 55.74, 37.64, 55.76],
format: 'svg',
style: 'blueprint'
})
});
const { task_id } = await response.json();
// Wait via REST polling (every 2 seconds)
while (true) {
const statusResp = await fetch(`${BASE_URL}/status/${task_id}`, {
headers: { 'X-API-Key': API_KEY }
});
const data = await statusResp.json();
console.log(`Progress: ${data.progress || 0}% — ${data.step || ''}`);
if (data.status === 'completed') {
window.location.href = data.download_url;
return;
}
if (data.status === 'failed') {
throw new Error(data.error);
}
await new Promise((r) => setTimeout(r, 2000));
}
}
API Endpoints
POST /api/render
Create an export task.
Parameters:
- bbox (array) — bounding box [min_lon, min_lat, max_lon, max_lat].
- polygon (GeoJSON) — arbitrary polygon instead of bbox.
- format (string) — export format (geojson, svg, pdf, dwg, stl, etc.).
- style (string) — map style (default, blueprint, vintage, neon, satellite, etc.).
- detail_level (int, 1-6) — detail level (1=minimum, 6=maximum).
- crs (string) — coordinate system (EPSG:4326, EPSG:32637, msk-77, etc.).
- layers (array) — which layers to include (roads, buildings, water, green, etc.).
GET /api/status/{task_id}
Task status.
Response:
{
"task_id": "abc123",
"status": "processing",
"progress": 65,
"created_at": "2026-03-15T10:00:00Z",
"format": "geojson",
"bbox": [37.60, 55.74, 37.64, 55.76]
}
Statuses: queued -> processing -> completed / failed.
Task progress (polling)
The current API uses REST polling via GET /api/status/{task_id} to track progress. The WebSocket endpoint /ws/task/{task_id} exists only as a stub (it immediately closes with code 1001 "Not implemented. Poll /api/status/{task_id}") and is reserved for a future Celery -> Redis Pub/Sub bridge — do not use it in production code.
Recommended interval is 2-5 seconds. The /api/status/{task_id} response contains status, progress (0-100), step (current stage), error, and a files field with download URLs on completion:
{"status": "processing", "progress": 45, "step": "rendering"}
{"status": "completed", "progress": 100, "files": {"geojson": "..."}}
GET /api/formats
List of available formats with metadata.
GET /api/styles
List of available map styles.
Geo-Analytics API
In addition to export, the API provides territory analytics:
# Scoring for a point
scoring = requests.get(f"{BASE_URL}/scoring", params={
"lat": 55.7558,
"lon": 37.6176
}, headers={"X-API-Key": API_KEY}).json()
print(f"Walk Score: {scoring['walk_score']}")
print(f"Green Score: {scoring['green_score']}")
print(f"Livability: {scoring['livability_index']}")
# Area statistics
stats = requests.get(f"{BASE_URL}/area-stats", params={
"bbox": "37.60,55.74,37.64,55.76"
}, headers={"X-API-Key": API_KEY}).json()
print(f"Buildings: {stats['buildings_count']}")
print(f"Roads: {stats['roads_total_km']} km")
print(f"Green area: {stats['green_area_km2']} km2")
Error Handling
The API returns standard HTTP codes:
| Code | Reason | Action |
|---|---|---|
| 400 | Invalid bbox or format; BBOX_TOO_LARGE — area exceeds the technical limit | Check parameters; on BBOX_TOO_LARGE reduce the bbox |
| 401 | Invalid API key | Check X-API-Key |
| 402 | Payment or login required (no_credits / login_required) | Pay for the file or top up the wallet |
| 429 | Rate limit exceeded | Wait, retry after Retry-After |
| 500 | Server error | Retry after 30 seconds |
Recommendation: use exponential backoff for retry logic.
Integrate map export into your applications via the osm2cdr.ru API. Documentation and examples are available on the site at /docs/.