V2X Intersection
The V2X MAP and SPAT application brings your intersection into the era of connected and automated vehicles — enabling full support for MAP (Geometric Intersection Description/Map Data) and SPaT (Signal Phase and Timing) messages.
This powerful app works seamlessly with just about any traffic controller, transforming your existing infrastructure into a V2X-ready hub without requiring costly replacements.
It generates and broadcasts standardized MAP and SPaT data via your RSU (Roadside Unit), providing approaching connected vehicles with precise, real-time information about intersection geometry, lane configurations, and current/future signal states.

Concepts
MAP Message
This is like sending a detailed digital blueprint of the intersection to your car.
It tells the car exactly:
- Where each lane starts and ends
- Which lanes go straight, turn left, turn right, etc.
- How lanes connect
- Stop lines, crosswalks, and other road rules
Without the MAP, the car wouldn't know which light controls which lane — it's the static "map" that gives context.
SPAT Message
This is the real-time status update from the traffic light.
It tells your car:
- Which lights are currently red, yellow, or green
- How many seconds are left until the light changes (e.g., "Green for 12 more seconds")
- Sometimes even predicted future changes
It updates super frequently (often every 1/10th of a second) so your car always knows the latest timing.
RSU (Road Side Unit)
This is just a smart radio box (usually mounted on traffic light poles, signs, or other roadside spots). It connects to the connected-car network and broadcasts important messages directly to nearby vehicles.
Your app sends the MAP and SPaT messages to the RSU, which then blasts them out frequently so cars approaching the intersection always get the latest info in time.
- SPaT (the live traffic light status and countdown) uses a "send once and forget" style — the RSU gets the update, transmits it right away (often 10 times per second or every 100ms in real deployments), then discards it. When the light changes or a new timing update comes, the app sends a fresh one — keeping everything super current without wasting airtime.
- MAP (the fixed intersection blueprint showing lanes, turns, etc.) uses a "store and repeat" style — the RSU holds onto it since the intersection layout rarely changes. It still broadcasts it repeatedly (typically every 1–5 seconds or so) so any new car rolling up hears the geometry immediately and can make sense of the SPaT data.
It works with most modern RSUs that follow the common standard (NTCIP-1218), which lets cities manage these smart radios easily.
PSID (Provider Service Identifier)
This is like the channel name or topic tag for the message.
Cars pick up tons of wireless signals all the time (emergency braking warnings, road hazard alerts, ice on the road, etc.). The PSID tells the car exactly what kind of info it's getting: "This is intersection map & traffic light timing data!"
For MAP and SPaT messages (intersection safety stuff), they typically use a dedicated PSID (often the one assigned for intersection applications in the U.S. standards). You just select the right PSID in the app, and your MAP/SPaT messages go out on the correct "channel" so cars know to process them for smart features like red-light warnings, speed advice to catch green lights, or smoother self-driving decisions.
User Interface
Status Page
This page provides information about what is being broadcast to the RSU
- Information on what the SPAT message is broadcasting
- Status of the RSU
- Lane movement status. This will list which movements are available and what state they're in
MAP geometry
- Blue - crosswalk
- Green - bike lane
- Pink - vehicle lane
- Orange - railroad
- Lane number
- Information on MAP message broadcasting
- Settings


Settings
- Enable/disable the application
- Traffic Signal interface that you want to broadcast
- RSU to send MAP and SPAT messages to
- Intersection ID - set to any number that is unique systemwide
- SPAT broadcast settings
- MAP broadcast settings
REST API
PUT /api/app/v2x-intersection
PUT /api/app/v2x-intersection HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Content-Type: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61
{"settings":{"enabled":true,"intersection":{"id":10012},"interface":{"traffic-signal":16,"v2x":21},"spat":{"transmission":500,"channel":172,"priority":1,"psid":"0p8002"},"map":{"refresh":60,"channel":172,"priority":1,"transmission":500,"psid":"0pe0000017"}}}
HTTP/1.1 200 OK
Content-Type: application/json
settings.enabled boolean | Enable/disable the application |
settings.interface.v2x number | Interface ID of the RSU |
settings.interface.traffic-signal number | Interface ID of the traffic signal |
settings.intersection.id number | Intersection ID transmitted in the MAP message |
settings.map.transmission number | Rate, in milliseconds, to transmit the MAP message. This is the interval value sent to the RSU for the SRM (store and repeat message). |
settings.map.refresh number | How frequent, in seconds, the MAP message is re-uploaded to the RSU for SRM broadcasting |
settings.map.channel number | V2X channel to broadcast the MAP message on |
settings.map.priority number | V2X priority to assign to the MAP message. See IEEE 1609.3 for the values |
settings.map.psid string | V2X PSID to assign to the MAP message |
settings.spat.channel number | V2X channel to broadcast the SPAT message on |
settings.spat.priority number | V2X priority to assign to the SPAT message. See IEEE 1609.3 for the values |
settings.spat.psid string | V2X PSID to assign to the SPAT message |
settings.spat.transmission number | Minimum rate that the SPAT message will be broadcast at. A new SPAT message is sent in real-time when the state of the traffic signal changes, but if a SPAT has not been generated within this minimum time, then it will automatically send out a SPAT message of the current state of the signal |
GET /api/app/v2x-intersection
GET /api/app/v2x-intersection HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61
HTTP/1.1 200 OK
Content-Type: application/json
{"app":{"name":"v2x-intersection","settings":{"_version_":[2,71],"enabled":true,"interface":{"traffic-signal":16,"v2x":21},"intersection":{"id":10012},"map":{"channel":172,"intersection":{"layer-id":0},"priority":1,"psid":"0pe0000017","refresh":60,"transmission":500},"spat":{"channel":172,"priority":1,"psid":"0p8002","transmission":500}},"defaults":{"enabled":false,"interface":{"traffic-signal":0,"v2x":0},"intersection":{"id":0},"map":{"channel":178,"intersection":{"lanes":null,"layer-id":0},"psid":"0p8003","refresh":60,"transmission":500},"spat":{"channel":178,"priority":1,"psid":"0p8002","transmission":500}},"manifest":{"description":"Enables V2X capabilities for a traffic intersection","name":"V2X Intersection","version":"1.0.0"}}}
GET /api/app/v2x-intersection/status
GET /api/app/v2x-intersection/status HTTP/1.1
Host: 127.0.0.1
Accept: application/json
Authorization: bearer 109b893ceb1c26e3e64e9abf7cdd2aa1c0d25f61
HTTP/1.1 200 OK
Content-Type: application/json
{"status":{"map":{"lanes":[{"approach":4,"connections":null,"departure":0,"geometry":[[47.617393845895876,-122.2011320898677],[47.617396557923634,-122.20148077703963],[47.61742819823725,-122.20148211814414],[47.61742639021985,-122.20113745428573]],"id":1,"type":"vehicle"},{"approach":4,"connections":null,"departure":0,"geometry":[[47.617432718280504,-122.20147943593513],[47.61745351047436,-122.20148077703963],[47.61745079844953,-122.20118171073447],[47.617429102245936,-122.20118305183898]],"id":2,"type":"vehicle"},{"approach":4,"connections":[{"maneuver":"straight","state":"stop-and-remain","to":4}],"departure":0,"geometry":[[47.61745351047436,-122.20148211814414],[47.61748334273806,-122.20148345924865],[47.61747701468354,-122.20117366410743],[47.61744989444124,-122.20117366410743]],"id":3,"type":"vehicle"},{"approach":0,"connections":null,"departure":14,"geometry":[[47.61745170245783,-122.20197564460288],[47.61748063071478,-122.20197430349837],[47.617481534722565,-122.20223715998183],[47.61745441448261,-122.20223715998183]],"id":4,"type":"vehicle"},{"approach":4,"connections":null,"departure":0,"geometry":[[47.617327316420536,-122.2015464911605],[47.61754970251363,-122.20153039790641],[47.6175623586043,-122.20155185557853],[47.61754879850702,-122.2015813598777],[47.61732370037871,-122.20158806540023],[47.617311948240975,-122.20156928993713]],"id":5,"type":"crosswalk"}],"message":{"revision":0,"timestamp":1750886883}},"spat":{"message":{"revision":110,"timestamp":1750886939},"signal-groups":[{"id":6,"state":"stop-and-remain"},{"id":4,"state":"stop-and-remain"},{"id":16,"state":"stop-and-remain"},{"id":1,"state":"stop-and-remain"},{"id":14,"state":"stop-and-remain"},{"id":8,"state":"stop-and-remain"},{"id":22,"state":"stop-and-remain"},{"id":12,"state":"permissive-movement-allowed"},{"id":3,"state":"stop-and-remain"},{"id":24,"state":"stop-and-remain"},{"id":2,"state":"protected-movement-allowed"},{"id":7,"state":"stop-and-remain"},{"id":18,"state":"stop-and-remain"},{"id":26,"state":"stop-and-remain"},{"id":5,"state":"protected-clearance"},{"id":28,"state":"stop-and-remain"}]},"traffic-signal":{"state":{"name":"operational","timestamp":1750886703}},"v2x":{"state":{"name":"inoperative","timestamp":1750886703}}}}
status.v2x.state.name string | Current state of the RSU Values: unknown, inoperative, operational, fault |
status.v2x.state.timestamp number | Unix epoch timestamp, in seconds, of when it went into this state |
status.traffic-signal.state.name string | Current state of the traffic signal Values: unknown, inoperative, operational, fault |
status.traffic-signal.state.timestamp number | Unix epoch timestamp, in seconds, of when it went into this state |
status.spat.message.revision number | Last SPAT message revision number that was broadcast |
status.spat.message.timestamp number | Unix epoch timestamp, in seconds, of when the last SPAT message was broadcast |
status.spat.signal-groups[].id number | Signal group ID. Mapped to specific movements |
status.spat.signal-groups[].state string | State of this signal group. See V2X SPAT specification for possible values |
status.map.message.revision number | Last MAP message revision number that was sent to the RSU |
status.map.message.timestamp number | Unix epoch timestamp, in seconds, of when the last MAP message was sent to the RSU |
status.map.lanes[] array | The list of lanes being broadcast in the MAP message |
status.map.lanes[].approach number | Approach ID. A value of 0 indicates that this is not an approach |
status.map.lanes[].departure number | Departure ID. A value of 0 indicates that this is not a departure |
status.map.lanes[].id number | Lane ID |
status.map.lanes[].type number | Type of lane Values: vehicle, crosswalk, bike, tracked-vehicle |
status.map.lanes[].geometry[] array[latitude,longitude] | Points that make up the geometry of the lane. Connecting the points will draw the polygon outlining the lane on a GIS map |
status.map.lanes[].connections[] array | A list of connections (or movements) permitted from this lane. Connections are links between 2 lanes, a movement, and the state of that movement from SPAT |
status.map.lanes[].connections[].id number | ID of the lane ID this lane connects with |
status.map.lanes[].connections[].state string | The current state of the signal group governing this movement |
status.map.lanes[].connections[].maneuver string | The maneuver travelers execute when traveling between these 2 lanes |