━━ 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 · NO ACCOUNT NEEDED

GET /v2/entities/nearby

Query a point and a radius, get back every entity (community alerts, chargers, cameras, feed entities) in JSON. No API key, no session — 60 requests/minute as a guest, 120 with an account.

curl 'https://app.codriver.io/v2/entities/nearby?lat=45.4699&lng=-73.5461&radius=3000'
# {
#   "entities": [
#     { "id": "...", "kind_id": "alert.police",
#       "geom": { "type": "Point", "coordinates": [-73.54, 45.46] }, ... },
#     { "id": "...", "kind_id": "charger.supercharger", ... }
#   ],
#   "sources": [ { "id": "chargers", "status": "online", ... } ]
# }

Add sources[]= to narrow it to one source; the catalogue is at /v2/sources. CORS is not enabled, so call it server-side rather than from a browser. Full parameter reference on developer.codriver.io.

━━ 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 with a PATCH to the feed. Backoff doubles on each failure, capped at 1 hour. The URL must be https on a public hostname.

━━ KINDS · PLATFORM-OWNED CATALOG

18 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.hazard with 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, or observed_at without 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

Questions integrators actually ask.

Do I need an account to read?
No. /v2/entities/nearby answers without an account — 60 requests/minute as a guest, 120 with one. Call it from a server, a script or a shell pipeline: CORS is not enabled, so a browser on another origin can't fetch it directly.
How do I push my own data in?
Register a feed via POST /v2/feeds (one-time, requires a codriver session cookie). For a pull feed, give us an https URL that returns a JSON array of entities and we poll it on the interval you set (30s–1h) — a static file is a perfectly good feed. For a push feed, capture the one-time push_ingest_token and POST batches whenever you have updates. Full contract at developer.codriver.io.
Is my data visible to other users?
Private feeds are visible only to you (the owner). Register with visibility "public" to ask for a place in the shared catalogue: every new feed goes to a curator for review, and you get an email either way — usually within 24 hours. Review is manual and expects the feed to be useful, accurate and TOS-compliant. Plenty of feeds stay private by design.
What kinds can I use?
A platform-owned catalog with 18 kinds today: alert.* (police, accident, road-closed, construction, hazard with subtypes for pothole / animal / fog / ice / flooding / car_stopped / object_on_road), camera.* (speed + red_light + avg_speed), charger.* (supercharger + destination), and traffic.jam. Submit anything outside the catalog and the row is rejected. New kinds are added when there's a real reason — email [email protected].
What stability commitments do you make?
v1 contract: no breaking changes to the core fields (external_id, kind, lat, lng, properties, ttl_seconds, observed_at) without a 90-day deprecation window emailed to feed owners. Additive fields and new kinds are non-breaking. Existing kinds are never renamed.
Where does the data live?
Hetzner, Finland. All data hosted in the EU under GDPR. We refuse non-justice-system requests for user data on principle.

← Back to community alerts