━━ DEVELOPERS · DATA LAYER
Build with codriver. Open by default.
The community alerts, chargers, and cameras you see on the map ship behind an unauthenticated read endpoint. Provincial 511 integrations, partner traffic feeds, and hobby projects all land through the same two-endpoint surface: read what's there, push what you have. Open kinds catalog, documented contract, no proprietary lock-in.
━━ READ · PUBLIC, NO AUTH
GET /v2/entities/nearby
Query a bounding box, get back every entity (community alerts, chargers, cameras, feed entities) in JSON. No API key, no session. CORS-open. Rate-limited by IP.
curl 'https://app.codriver.io/v2/entities/nearby?bbox=-73.7,45.4,-73.5,45.6'
# [
# { "id": "...", "kind": "alert.police", "lat": ..., "lng": ..., ... },
# { "id": "...", "kind": "charger.supercharger", ... },
# ...
# ]Drop this URL into a Mapbox geojson source, a Leaflet layer, or any shell pipeline. The shape is stable per the v1 contract below.
━━ WRITE · YOUR FEEDS, YOUR LAYER
POST /v2/feeds
Register a feed once, then either push entities (you POST when you have updates) or have us pull a URL you control on a cadence you set. Same payload shape either way. Feeds map to a layer you own; private by default.
Push feed
# 1. Register (sign in at codriver.io first so the session cookie is sent):
curl -X POST 'https://app.codriver.io/v2/feeds' \
-H 'Content-Type: application/json' \
--cookie /tmp/cookies.txt \
-d '{ "name": "My Traffic Feed", "direction": "push", "visibility": "private" }'
# → { "feed": { ... }, "push_ingest_token": "cdrf_..." } # store this NOW
# # (visible exactly once)
# 2. Push entities whenever you have updates:
TOKEN="cdrf_..."
curl -X POST "https://app.codriver.io/v2/feeds/$TOKEN/entities" \
-H 'Content-Type: application/json' \
-d '[
{ "external_id": "incident-2026-05-22-001",
"kind": "alert.road_closed",
"lat": 45.5017, "lng": -73.5673,
"properties": { "street": "René-Lévesque", "reason": "downed line" },
"ttl_seconds": 3600 }
]'
# → { "accepted": 1, "rejected": 0, "errors": [] }Pull feed
curl -X POST 'https://app.codriver.io/v2/feeds' \
-H 'Content-Type: application/json' \
--cookie /tmp/cookies.txt \
-d '{
"name": "MyCity 311 Feed",
"direction": "pull",
"pull_url": "https://api.mycity.example/311.json",
"pull_auth_header": "X-API-Key: your-key-here",
"pull_interval_seconds": 300
}'Pull interval is clamped to [30s, 3600s]. We auto-disable after 20 consecutive failures; re-enable in Settings. Backoff doubles on each failure, capped at 1 hour.
━━ KINDS · PLATFORM-OWNED CATALOG
17 kinds today. New ones added on real demand.
Your payload's kind must be one of:
- Alerts:
alert.police,alert.accident,alert.road_closed,alert.construction,alert.hazardwith subtypes (.car_stopped,.object_on_road,.pothole,.animal,.fog,.ice,.flooding) - Cameras (persistent):
camera.speed,camera.red_light,camera.avg_speed - Chargers (persistent):
charger.supercharger,charger.destination - Traffic:
traffic.jam
Anything outside the catalog is rejected at ingest. New kinds are added when there's a real use case — email [email protected] with a request.
━━ STABILITY · v1 CONTRACT
Promises we keep.
- No breaking changes to
external_id,kind,lat,lng,properties,ttl_seconds, orobserved_atwithout a 90-day deprecation window announced via email to feed owners. - Additive fields and new kinds are non-breaking and may ship at any time.
- Existing kind ids never get renamed.
- EU data residency. All entities, feeds, and user data live on Hetzner Helsinki — GDPR coverage, out of reach of US data acts. We refuse non-justice-system requests for user data on principle.
━━ FULL SPEC + CONTACT
Going deeper.
The canonical reference wiki is at developer.codriver.io — deeper coverage of each kind, error code, integration pattern, and stability commitment beyond what this page summarises. The engineering source-of-truth markdown alongside the code lives in the driving-app repo at codriver.io/docs/EXTERNAL-FEEDS.md.
For feed-spec questions, layer-approval requests, or bugs, email [email protected].
━━ FAQ