Overview
ATLAS (Advanced Tallahassee Live Automated Signals) is a V2X (Vehicle-to-Everything) signal visualization system for Tallahassee and Leon County, Florida. The external API provides real-time data from traffic signal controllers via the SAE J2735 standard.
Available Data Types
| Type | Name | Description |
|---|---|---|
spat | Signal Phase and Timing | Real-time signal states, phase timing, and countdown data for each intersection |
map | MAP Data | Intersection geometry including lane configurations, reference points, and approach nodes |
tim | Traveler Information | Advisories, work zones, hazard warnings, and road condition notices |
bsm | Basic Safety Message | Vehicle position, speed, heading, and acceleration data |
Base URL
https://<host>/api/v1/
Replace <host> with the hostname or IP address of the ATLAS server
provided to you by the ATLAS administrator.
Quick Start
-
Obtain an API key
Contact the ATLAS administrator to request an API key. You will receive a key in the formatatlas_live_followed by 48 alphanumeric characters. -
Test connectivity
Verify your key works by querying the status endpoint (public, no key needed):
Then test with your key:curl https://<host>/api/v1/statuscurl -H "X-API-Key: YOUR_KEY" https://<host>/api/v1/snapshot/spat -
Connect to live SSE stream
Open a persistent connection to receive real-time events:
Thecurl -N -H "X-API-Key: YOUR_KEY" https://<host>/api/v1/stream/spat-Nflag disables output buffering so events appear immediately.
Authentication
An API key is required for all data endpoints. Utility endpoints (status, intersections) are public.
Providing Your Key
| Method | Usage | Preferred |
|---|---|---|
X-API-Key header |
curl -H "X-API-Key: YOUR_KEY" ... |
Yes (recommended) |
?api_key= query parameter |
curl "...?api_key=YOUR_KEY" |
No (use for browser EventSource) |
Key Format
API keys follow the format: atlas_live_ prefix followed by 48 alphanumeric
characters. Example: atlas_live_aBcDeFgHiJkLmNoPqRsTuVwXyZ012345678901234567
Scopes
Each API key is assigned scopes that control which message types it can access. Attempting to access a type outside your scopes returns a 403 error.
| Scope | Grants Access To |
|---|---|
spat | SPaT streaming, snapshots, schemas, and samples |
map | MAP streaming, snapshots, schemas, and samples |
tim | TIM streaming, snapshots, schemas, and samples |
bsm | BSM streaming, snapshots, schemas, and samples |
* | All message types (wildcard) |
Endpoints Reference
ATLAS provides 18 endpoints organized into 5 categories.
Server-Sent Events for real-time data. Connections remain open indefinitely.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/stream |
Key | All message types combined into one stream |
| GET | /api/v1/stream/spat |
Key + scope:spat | SPaT events only |
| GET | /api/v1/stream/map |
Key + scope:map | MAP events only |
| GET | /api/v1/stream/tim |
Key + scope:tim | TIM events only |
| GET | /api/v1/stream/bsm |
Key + scope:bsm | BSM events only |
SSE Stream Format
Each event follows the W3C Server-Sent Events specification:
event: spat
data: {"intersection_id":"0_5433","timestamp":1706800000,...}
id: 42
A heartbeat comment (:ping) is sent every 15 seconds to keep the connection alive.
Clients should implement auto-reconnect with exponential backoff.
Returns the latest cached data as a single JSON response (not streaming).
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/snapshot/spat |
Key + scope:spat | Current SPaT data for all intersections |
| GET | /api/v1/snapshot/map |
Key + scope:map | Current MAP data for all intersections |
| GET | /api/v1/snapshot/tim |
Key + scope:tim | Current TIM data |
| GET | /api/v1/snapshot/bsm |
Key + scope:bsm | Current BSM data |
Returns the JSON Schema describing the structure of each message type.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/schema/spat |
Key | SPaT event JSON Schema |
| GET | /api/v1/schema/map |
Key | MAP event JSON Schema |
| GET | /api/v1/schema/tim |
Key | TIM event JSON Schema |
| GET | /api/v1/schema/bsm |
Key | BSM event JSON Schema |
Replay recorded sample data for testing without needing a live data feed.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/stream/sample/spat |
Key + scope:spat | Replay sample SPaT data |
| GET | /api/v1/stream/sample/map |
Key + scope:map | Replay sample MAP data |
| GET | /api/v1/stream/sample/tim |
Key + scope:tim | Replay sample TIM data |
| GET | /api/v1/stream/sample/bsm |
Key + scope:bsm | Replay sample BSM data |
Public endpoints that do not require authentication.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/v1/status |
Public | Service health: uptime, SSE client count, data freshness |
| GET | /api/v1/intersections |
Public | List of active intersections with IDs and coordinates |
Message Types
Below are representative JSON payloads for each message type. All data uses sanitized coordinates from Tallahassee intersections.
SPaT (Signal Phase and Timing)
Contains current signal states and timing for each phase at an intersection.
{
"type": "SPAT",
"data": {
"SPAT": {
"intersections": [
{
"id": {
"region": 0,
"id": 5433
},
"revision": 2,
"status": "0000000000000000",
"states": [
{
"signalGroup": 2,
"state-time-speed": [
{
"eventState": "permissive-Movement-Allowed",
"timing": {
"minEndTime": 12340,
"maxEndTime": 15670,
"likelyTime": 14200
}
}
]
},
{
"signalGroup": 6,
"state-time-speed": [
{
"eventState": "stop-And-Remain",
"timing": {
"minEndTime": 25600
}
}
]
}
],
"moy": 346521,
"timeStamp": 23456
}
]
}
}
}
MAP (Intersection Geometry)
Describes intersection layout including lane configurations and reference points.
{
"type": "MAP",
"data": {
"MapData": {
"msgIssueRevision": 3,
"layerType": "intersectionData",
"intersections": [
{
"id": {
"region": 0,
"id": 5433
},
"revision": 3,
"refPoint": {
"lat": 304434500,
"long": -842808300,
"elevation": 150
},
"laneWidth": 366,
"laneSet": [
{
"laneID": 1,
"laneAttributes": {
"directionalUse": "10",
"sharedWith": "0000000000",
"laneType": {"vehicle": "00000000"}
},
"maneuvers": "010000000000",
"nodeList": {
"nodes": [
{"delta": {"node-XY3": {"x": 145, "y": -1023}}},
{"delta": {"node-XY3": {"x": 32, "y": -845}}}
]
},
"connectsTo": [
{"connectingLane": {"lane": 10, "maneuver": "010000000000"}}
]
}
],
"speedLimits": [
{"type": "vehicleMaxSpeed", "speed": 560}
]
}
]
}
}
}
TIM (Traveler Information Message)
Advisories, work zone alerts, and hazard warnings broadcast to travelers.
{
"type": "TIM",
"data": {
"TravelerInformation": {
"msgCnt": 1,
"timeStamp": 487234,
"packetID": "00000000001A",
"dataFrames": [
{
"sspTimRights": 0,
"frameType": "advisory",
"msgId": {
"roadSignID": {
"position": {
"lat": 304450000,
"long": -842790000
},
"viewAngle": "1111111111111111",
"mutcdCode": "warning"
}
},
"startYear": 2026,
"startTime": 346521,
"durationTime": 1440,
"priority": 5,
"sspLocationRights": 3,
"regions": [
{
"name": "Mahan Dr Construction Zone",
"anchor": {
"lat": 304450000,
"long": -842790000
},
"laneWidth": 500,
"directionality": "both",
"description": {
"path": {
"offset": {
"xy": {
"nodes": [
{"delta": {"node-LatLon": {"lat": 304451000, "lon": -842788000}}},
{"delta": {"node-LatLon": {"lat": 304452000, "lon": -842786000}}}
]
}
}
}
}
}
],
"sspMsgRights1": 1,
"sspMsgRights2": 1,
"content": {
"advisory": [
{"item": {"itis": 7426}},
{"item": {"text": "Road work ahead - reduce speed"}}
]
}
}
]
}
}
}
BSM (Basic Safety Message)
Vehicle position, speed, heading, and other safety-critical data.
{
"type": "BSM",
"data": {
"BasicSafetyMessage": {
"coreData": {
"msgCnt": 42,
"id": "a1b2c3d4",
"secMark": 34521,
"lat": 304440000,
"long": -842800000,
"elev": 152,
"accuracy": {
"semiMajor": 50,
"semiMinor": 50,
"orientation": 0
},
"transmission": 0,
"speed": 1500,
"heading": 18000,
"angle": 0,
"accelSet": {
"long": 0,
"lat": 0,
"vert": 0,
"yaw": 0
},
"brakes": {
"wheelBrakes": 0,
"traction": 0,
"abs": 0,
"scs": 0,
"brakeBoost": 0,
"auxBrakes": 0
},
"size": {
"width": 200,
"length": 500
}
}
}
}
}
Query Parameters
| Parameter | Applies To | Description |
|---|---|---|
intersections |
SSE streams, snapshots | Comma-separated intersection IDs to filter results. Example: ?intersections=0_5433,0_5434 |
bbox |
SSE streams, snapshots | Bounding box filter: ?bbox=lat1,lon1,lat2,lon2. Reserved for future use; accepted but not yet applied. |
api_key |
All authenticated endpoints | Alternative to X-API-Key header. Required for browser EventSource which cannot set custom headers. |
Intersection ID Format
Intersection IDs use the format {region}_{intersection_id} where region is
typically 0 and the intersection_id is assigned by the traffic signal controller.
Use the /api/v1/intersections endpoint to discover available IDs.
Error Reference
All errors return a JSON body with a detail field describing the issue.
400 Bad Request
The request contains an invalid message type.
{"detail": "Invalid message type 'xyz'. Must be one of: bsm, map, spat, tim"}
401 Unauthorized
No API key was provided, or the key is invalid, revoked, or expired.
{"detail": "API key required. Provide via X-API-Key header or ?api_key= query parameter."}
403 Forbidden
The API key does not have the required scope for the requested message type.
{"detail": "Key not authorized for 'bsm'. Allowed: ['spat', 'map']"}
404 Not Found
The requested resource or endpoint does not exist.
{"detail": "Not Found"}
429 Too Many Requests
The API key has exceeded its concurrent connection limit.
{"detail": "Connection limit reached. Limit: 5 concurrent, currently using 5."}
503 Service Unavailable
SSE streaming is not available (the service may be starting up or SSE is disabled).
{"detail": "SSE streaming is not available"}
Rate Limits and Connection Limits
Key Tiers
| Tier | Scopes | Max Concurrent SSE Connections |
|---|---|---|
basic | Typically 1-2 types (e.g., spat, map) | 2 |
standard | Typically 3-4 types | 5 |
full | All types (*) | 10 |
Limits
- Per-key concurrent SSE connections: Varies by tier (see table above). Exceeding the limit returns HTTP 429.
- Global maximum SSE clients: 100 simultaneous connections across all keys.
- Snapshot and schema endpoints: No request rate limit. These are standard HTTP requests, not long-lived connections.
Network Requirements
- HTTPS required — All API traffic must use port 443 (TLS).
- Long-lived connections — SSE streams remain open indefinitely. Your HTTP client and any proxies must not impose a request timeout.
- Firewall rules — Allow outbound HTTPS (TCP 443) to the ATLAS server IP.
- Keep-alive — The server sends a
:pingheartbeat comment every 15 seconds. If you do not receive data or a heartbeat for 30+ seconds, the connection may be broken. - Reconnection — Clients should implement auto-reconnect with exponential backoff (e.g., 1s, 2s, 4s, 8s, max 30s). The browser
EventSourceAPI handles this automatically.
Recommended Client Environments
| Environment | Notes |
|---|---|
| Server-side (Python, Node.js, curl) | Recommended for production integrations. Use X-API-Key header. |
| Browser (JavaScript) | Use ?api_key= query parameter since EventSource cannot set custom headers. Be aware the key is visible in the URL. |
EventSource API does not support custom
HTTP headers. When connecting from a browser, pass the API key as a query parameter
(?api_key=YOUR_KEY). This exposes the key in browser history and server
logs. For production systems, prefer server-side consumers.
Client Examples
curl
# Stream all SPaT events (press Ctrl+C to stop)
curl -N -H "X-API-Key: YOUR_KEY" https://<host>/api/v1/stream/spat
# Get current snapshot of all MAP data
curl -H "X-API-Key: YOUR_KEY" https://<host>/api/v1/snapshot/map
# Filter stream by specific intersections
curl -N -H "X-API-Key: YOUR_KEY" \
"https://<host>/api/v1/stream/spat?intersections=0_5433,0_5434"
# Check service status (no key required)
curl https://<host>/api/v1/status
# Get JSON Schema for SPaT events
curl -H "X-API-Key: YOUR_KEY" https://<host>/api/v1/schema/spat
Python (with sseclient-py)
Install the client library: pip install sseclient-py requests
import sseclient
import requests
import json
# Connect to the SPaT stream
url = "https://<host>/api/v1/stream/spat"
headers = {"X-API-Key": "YOUR_KEY"}
response = requests.get(url, headers=headers, stream=True, verify=False)
client = sseclient.SSEClient(response)
for event in client.events():
print(f"Event type: {event.event}")
data = json.loads(event.data)
print(f" Intersection: {data.get('intersection_id', 'N/A')}")
print(f" Data: {json.dumps(data, indent=2)[:200]}...")
print()
JavaScript (EventSource)
For browser-based consumers. Note: API key must be passed as a query parameter.
// Connect to the SPaT stream
const source = new EventSource(
"https://<host>/api/v1/stream/spat?api_key=YOUR_KEY"
);
// Listen for SPaT events
source.addEventListener("spat", (event) => {
const data = JSON.parse(event.data);
console.log("SPaT update:", data);
});
// Handle connection errors
source.onerror = (error) => {
console.error("SSE connection error:", error);
// EventSource will automatically reconnect
};
// Listen for all event types on a combined stream
// const allSource = new EventSource(
// "https://<host>/api/v1/stream?api_key=YOUR_KEY"
// );
// allSource.addEventListener("spat", handler);
// allSource.addEventListener("map", handler);
// allSource.addEventListener("tim", handler);
// allSource.addEventListener("bsm", handler);
Node.js (eventsource package)
Install: npm install eventsource
const EventSource = require("eventsource");
const url = "https://<host>/api/v1/stream/spat";
const source = new EventSource(url, {
headers: { "X-API-Key": "YOUR_KEY" }
});
source.addEventListener("spat", (event) => {
const data = JSON.parse(event.data);
console.log("SPaT:", data);
});
source.onerror = (err) => {
console.error("Connection error:", err);
};