Every US state and Canadian province runs its own 511 traveler information system. They all serve the same kind of data — traffic incidents, cameras, road conditions, message signs — but every single one does it differently.
I spent the past year building Road511, a unified API that normalizes data from 57 jurisdictions into one consistent REST endpoint. Here's what I learned about wrangling 30+ incompatible APIs into a single schema.
The Problem
Let's say you want traffic camera feeds for a route from New York to Chicago. You'll need to integrate:
New York, Pennsylvania, Ohio, Indiana, Illinois — five states, five completely different 511 systems. Different authentication, different response formats, different field names for the same data. Some serve REST JSON, some serve map-layer markers, some require an API key, some take query parameters and some take request bodies. And that's just cameras — add events, road conditions, and message signs, and you're looking at 20+ integrations for one cross-state route.
Now multiply that by the entire continent.
The Format Zoo
The same "traffic event" arrives in wildly different shapes depending on the platform. Some states publish clean JSON REST APIs; many use Esri ArcGIS FeatureServer query formats; two dozen publish GeoJSON via the Work Zone Data Exchange (WZDx) standard; others expose map-layer markers, XML portals, or GraphQL endpoints. A handful ship obfuscated binary formats. Field names, authentication, pagination, and coordinate systems differ at every stop.
Same data, wildly different delivery. Unifying all of it — and keeping it unified as feeds silently change shape — is the hard part, and it's the whole point of Road511.
The Normalized Model
Everything converges into two tables:
traffic_events — time-bounded incidents with lifecycle tracking:
type TrafficEvent struct {
ID string
Source string // "on", "ga", "tx"
Jurisdiction string // "ON", "GA", "TX"
Type EventType // incident, construction, closure, weather
Severity Severity // minor, moderate, major, critical
Status EventStatus // active, archived
Title string
Description string
AffectedRoads []string
Direction string
LanesAffected string
Latitude, Longitude float64
StartTime time.Time
EndTime *time.Time
EstimatedEndTime *time.Time
RoadClass string // interstate, us_highway, state_highway, local
Metadata json.RawMessage // source-specific fields preserved
}
features — generic table for everything else. Cameras, signs, weather stations, rest areas, bridge clearances, truck routes, EV charging — all use the same table with a feature_type discriminator and type-specific fields in a JSONB properties column. Adding a new data type requires zero schema migrations.
The Hard Parts
1. Lifecycle Tracking
A traffic incident isn't a static record. It escalates (minor to major), lanes change, ETAs shift, and eventually it clears. Each source reports the current state differently — some send updates, some just stop including the event.
The solution: diff the current state against the previous fetch. Track every change in an event_history table — severity changes, description updates, lane changes, archival. This enables analytics like clearance time percentiles and corridor reliability scoring.
2. Coordinate Chaos
Most sources send standard WGS84 lat/lng, but plenty don't — coordinates arrive in several different spatial reference systems, and some are buried inside non-standard binary payloads. Every source has to be detected and reprojected into one consistent system before the data is usable.
PostGIS handles the heavy lifting, but the unification work is in knowing what each source actually sends and transforming accordingly.
3. Rate Limiting at Scale
57 jurisdictions, each with multiple resource types (events, cameras, signs, weather), each polling every 1–5 minutes. That's hundreds of outbound requests per minute to external 511 systems.
The scheduler uses per-server semaphores with configurable concurrency limits and request gaps. Circuit breakers back off on repeated failures. Adaptive backoff increases poll intervals when a source is slow or returning errors.
4. Schema-Free Feature Types
When I started, I had separate tables for cameras, signs, rest areas. Every new data type meant a migration. The pivot to a generic features table with JSONB properties was the best architectural decision in the project. Adding EV charging stations (100k+ from NREL) or bridge clearances (621k from FHWA) required zero schema changes.
The API
After all that normalization work, the API is straightforward:
Get active incidents in Ontario:
curl "https://api.road511.com/api/v1/events?jurisdiction=ON&type=incident&status=active" \
-H "X-API-Key: your_key"
{
"data": [
{
"id": "on_ev_12345",
"jurisdiction": "ON",
"type": "incident",
"severity": "major",
"title": "Multi-vehicle collision on Highway 401 WB",
"affected_roads": ["Highway 401"],
"direction": "Westbound",
"lanes_affected": "2 of 4 lanes closed",
"latitude": 43.6532,
"longitude": -79.3832,
"start_time": "2026-03-29T08:15:00Z",
"estimated_end_time": "2026-03-29T12:00:00Z"
}
],
"total": 85,
"limit": 100,
"offset": 0,
"has_more": false
}
Get traffic cameras in Georgia as GeoJSON:
curl "https://api.road511.com/api/v1/features/geojson?type=cameras&jurisdiction=GA" \
-H "X-API-Key: your_key"
Drop that response directly into Leaflet, Mapbox, or any GeoJSON-compatible tool.
Query truck restrictions along a corridor:
curl "https://api.road511.com/api/v1/truck/corridor?from_lat=41.88&from_lng=-87.63&to_lat=40.71&to_lng=-74.01&buffer_km=5" \
-H "X-API-Key: your_key"
Returns every bridge clearance, weight restriction, and truck route segment within 5km of the Chicago-to-NYC corridor that your truck can't clear.
What's in the Data
This isn't just traffic events. The normalized dataset includes:
- 10,000+ live cameras with direct image/stream URLs
- Dynamic message signs with current displayed text
- 621,000 bridges from the FHWA National Bridge Inventory (height, weight, condition)
- 479,000 truck route segments from the FHWA National Network
- 100,000+ EV charging stations from NREL
- Weather stations with real-time RWIS readings
- Rest areas and truck parking with amenity data
- Seasonal weight restrictions (spring load limits from multiple states)
- Road conditions (surface state, chain requirements)
- Work zones, ferries, weigh stations, service vehicles, and more
Tech Stack
- Go — chi router, pgx v5, slog
- PostgreSQL + PostGIS — spatial queries, GeoJSON generation, corridor intersection
- Redis — response caching, feature detail caching, rate-limit counters, webhook idempotency (mandatory — the API and worker refuse to start if Redis is unreachable)
- Vue 3 + Leaflet — live traffic map
Try It
The API is live with a free tier (no credit card):
- Live map — explore the data visually
- API docs — full endpoint reference
- Developer portal — sign up and get an API key
If you're building anything with traffic data — fleet routing, navigation, insurance risk, smart city dashboards — I'd love to hear what data you need. The hardest part isn't the code, it's knowing which 511 systems have which data in which format. After 57 jurisdictions, I've got a pretty good map.
Ready to try Road511?
Free 14-day trial. No credit card. All 65 jurisdictions included.
Get Free API Key Explore the Map