━━ 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.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 is public, unauthenticated, and CORS-open — drop the URL into a Mapbox layer, a Leaflet map, or a shell pipeline. We rate-limit by IP, not by key.
How do I push my own data in?
Register a feed via POST /v2/feeds (one-time, requires a codriver session cookie), capture the push_ingest_token from the response, then POST entities to /v2/feeds/:token/entities whenever you have updates. Or register a pull feed and we'll poll a URL of yours on the interval you specify.
Is my data visible to other users?
Private feeds are visible only to you (the owner). To request a public catalog promotion, email support after a few days of successful pushes — promotion is manual and requires the feed to be useful, accurate, and TOS-compliant. Most feeds stay private by design.
What kinds can I use?
A platform-owned catalog with ~17 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