Application Configuration Guide
Application Configuration API - User Guide <!-- omit from toc -->
Table of Contents
- Overview
- Getting Started
- Understanding Geofence Configurations
- Geofence Geometry
- Trigger Conditions
- Messages
- Message Standards
- Advanced Configuration Options
- Best Practices
- Common Use Cases
- Use Case 1: School Zone Speed Warning
- Use Case 2: Construction Zone Advisory
- Use Case 3: Wrong-Way Driver Detection
- Use Case 4: Hybrid Distribution - Critical Intersection Hazard
- Use Case 5: Mid-block Pedestrian Crossing Warning
- Use Case 6: OEM Client-Side Logic - Broadcast Zone Definition
- Use Case 7: Multi-Zone Parking Alert
- MQTT Integration
- Troubleshooting
- Common Errors and Solutions
- Error: "Invalid area location"
- Error: "AreaSizeError"
- Error: "Invalid trigger condition for geometry type"
- Error: "Polygon ring not closed"
- Error: "Polygon ring not counter-clockwise"
- Error: "Configuration not found" (404)
- Error: "Forbidden" (403)
- Error: "Too many requests" (429)
- Error: "Invalid configuration" (400)
- Common Errors and Solutions
- Additional Resources
Overview
The Edge Transportation Exchange (ETX) Application Configuration APIs allow you to create geofence-based message configurations that automatically send V2X messages to road users when specific conditions are met. These APIs enable you to:
- Define geographic zones using GeoJSON format
- Set trigger conditions (enter, leave, inside, crossing)
- Configure V2X messages (RSA alerts, TIM information, DENM notifications, or custom messages)
- Apply speed and direction filters
- Choose between targeted or broadcast distribution
- Manage multiple configurations per vendor
The configurations are distributed to Multi-Access Edge Computing (MEC) nodes where geofence violations are evaluated in real-time with low latency, ensuring rapid response to safety-critical events.
Getting Started
Authentication
All Application Configuration APIs require two authentication tokens from ThingSpace:
- Access/Bearer Token: Used for authorization
- Session/M2M Token: Used for authentication
- VendorID Header: Identifies your organization
For detailed instructions on obtaining these tokens:
- ThingSpace Quick Start Guide - Obtaining an Access Token
- ThingSpace Quick Start Guide - Obtaining a VZ-M2M Session Token
- ThingSpace API Video Guides
Example Request Headers:
Authorization: Bearer M2E3NTlkY2YtNTc4YS00MTcMDItYTNiMTE5ZTgwN2M4
SessionToken: 290386b7-dad7-8447-c50c-31648cc233ea
VendorID: VerizonETXAPI Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/application/configurations/geofence | Create a new configuration |
| GET | /api/v1/application/configurations/geofence/ids | List all configuration IDs for your vendor |
| GET | /api/v1/application/configurations/geofence?id={configId} | Get details of a specific configuration |
| PUT | /api/v1/application/configurations/geofence?id={configId} | Update an existing configuration |
| DELETE | /api/v1/application/configurations/geofence?id={configId} | Delete a configuration |
- Production:
https://imp.thingspace.verizon.com
Understanding Geofence Configurations
What is a Geofence Configuration?
A geofence configuration combines:
- Geographic boundaries - Defined using GeoJSON format
- Trigger conditions - When to send messages (enter, leave, inside, crossing)
- V2X messages - What to send (up to 10 messages per configuration)
- Filters - Speed and direction limits (optional)
- Distribution rules - How to deliver messages (targeted or broadcast)
Configuration Lifecycle
- Create - POST request returns a unique configuration ID (UUID)
- Activate - Set
isActive: trueto deploy to MECs - Update - Modify any aspect using PUT request
- Deactivate - Set
isActive: falseto temporarily disable - Delete - Remove configuration permanently
Important: All coordinates in your geofence must fall within a single MEC's coverage area. Configurations spanning multiple MECs will be rejected.
Geofence Geometry
Supported Geometry Types
The Application Configuration API supports standard GeoJSON geometry types:
| Geometry Type | Dimension | Use Case |
|---|---|---|
| LineString | 1D | Roads, lanes, boundaries that can be crossed |
| MultiLineString | 1D | Multiple separate lines (e.g., multiple lanes) |
| Polygon | 2D | Areas, zones, regions |
| MultiPolygon | 2D | Multiple separate areas (e.g., multiple intersections) |
Geometry Requirements
LineString
- Minimum: 2 coordinate points
- Maximum: 63 coordinate points
- Coordinates:
[longitude, latitude]in decimal degrees - Range: Longitude [-180, 180], Latitude [-180, 180]
Example:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-77.0366, 38.8977],
[-77.0360, 38.8980],
[-77.0354, 38.8983]
]
},
"properties": {}
}]
}MultiLineString
- Minimum: 2 LineStrings (must have MORE than 1 line)
- Maximum: 10 LineStrings
- Each LineString follows the same rules as single LineString
Example:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "MultiLineString",
"coordinates": [
[[-77.0366, 38.8977], [-77.0360, 38.8980]],
[[-77.0354, 38.8983], [-77.0348, 38.8986]]
]
},
"properties": {}
}]
}Polygon
- Minimum: 4 coordinate points (first and last must be identical to close the ring)
- Maximum: 63 coordinate points
- Ring Order: Counter-clockwise (required)
- Holes: Not currently supported (single ring only)
Critical Requirements:
- First and last points MUST be identical
- Ring MUST be in counter-clockwise order
- System validates ring closure and winding order
Example:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-77.0366, 38.8977],
[-77.0360, 38.8980],
[-77.0354, 38.8983],
[-77.0366, 38.8977]
]]
},
"properties": {}
}]
}MultiPolygon
- Minimum: 2 Polygons (must have MORE than 1 polygon)
- Maximum: 10 Polygons
- Each Polygon follows the same rules as single Polygon
Example:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[[[-77.0366, 38.8977], [-77.0360, 38.8980], [-77.0354, 38.8983], [-77.0366, 38.8977]]],
[[[-77.0400, 38.9000], [-77.0394, 38.9003], [-77.0388, 38.9006], [-77.0400, 38.9000]]]
]
},
"properties": {}
}]
}Area Size Limits
The system limits the geographic area covered by your geofence to ensure efficient processing:
- Maximum Coverage: 288 geohashes at precision level 7
- Calculation Method: System converts your geometry to geohashes and counts coverage
- Error: If area is too large, you'll receive
AreaSizeError
Tip: Use multiple smaller configurations instead of one large configuration if you exceed area limits.
Trigger Conditions
Trigger Types
Trigger conditions determine when messages are sent to road users:
| Trigger | Description | Valid For |
|---|---|---|
| enter | Message sent when road user enters the zone | Polygon, MultiPolygon |
| leave | Message sent when road user exits the zone | Polygon, MultiPolygon |
| inside | Message sent while road user is within the zone | Polygon, MultiPolygon |
| crossing | Message sent when road user crosses the line | LineString, MultiLineString |
Visual Guide to Trigger Conditions
Polygon Triggers (enter, leave, inside)
ENTER Trigger - Message sent when vehicle enters the geofence zone:
Vehicle moves from outside into the geofence. Trigger activates at zone boundary.
LEAVE Trigger - Message sent when vehicle exits the geofence zone:
Vehicle moves from inside to outside. Trigger activates when crossing boundary.
INSIDE Trigger - Message sent continuously while vehicle is within the zone:
Vehicle moves through the geofence. Trigger remains active throughout.
Example Use Cases:
- ENTER: School zone warning when vehicle enters
- LEAVE: "Thank you for driving safely" when exiting school zone
- INSIDE: Continuous speed limit reminder while in work zone
LineString Triggers (crossing)
CROSSING Trigger - Message sent when vehicle crosses a LineString boundary:
Vehicle crosses the vertical boundary line. Trigger activates at the crossing point.
Use Cases:
- Stop line detection at intersections
- Lane boundary violations
- Perimeter breach detection
- Wrong-way driver alerts
Multi-Geometry Triggers
MultiPolygon:
Vehicle entering Zone B demonstrates OR logic - trigger fires when entering ANY zone (A, B, or C).
- ENTER: Fires when vehicle enters ANY zone (1, 2, or 3)
- LEAVE: Fires when vehicle leaves ANY zone (1, 2, or 3)
- INSIDE: Fires when vehicle is inside ANY zone (1, 2, or 3)
Multiple independent zones = OR logic for triggers
MultiLineString:
Vehicle crossing Line B demonstrates OR logic - trigger fires when crossing ANY line (A, B, or C).
- CROSSING: Fires when vehicle crosses ANY line (A, B, or C)
Multiple independent lines = OR logic for crossing
Geometry-Specific Rules
For LineString and MultiLineString:
- ONLY
crossingtrigger is allowed - EXACTLY 1 trigger condition must be specified
- Any other trigger conditions will be rejected
For Polygon and MultiPolygon:
- ONLY
enter,leave, orinsidetriggers are allowed - NO
crossingtrigger permitted - Can specify 1 to 3 trigger conditions
- Multiple conditions are evaluated with OR logic
Multiple Trigger Conditions
When you specify multiple trigger conditions for a message, they are evaluated with OR logic:
"triggerConditions": ["enter", "inside"]This message will be sent when the road user either:
- Enters the geofence, OR
- Is inside the geofence
For MultiLineString/MultiPolygon:
- Trigger condition is met if ANY of the geometries satisfy it
- Example: For MultiPolygon with 3 polygons, "enter" triggers if user enters ANY of the 3 polygons
Messages
Each geofence configuration contains a messages array with 1-10 message objects. Each message defines:
- Who receives it (road user types)
- When it triggers (trigger conditions, limits)
- How it's delivered (distribution type and schedule)
- What content it contains (message type: generic, SAE, or ETSI)
The messages field follows the OpenAPI schema structure where each message inherits from MessageBase and includes one specific message type.
Message Fields
Every message in the messages array must include these fields:
isPrivate (boolean, required)
Defines whether the message is private or public.
-
true: Published under your Vendor ID, visible only to selected vendors -
false: Published under Public vendor ID, visible to all users -
Example:
"isPrivate": false
roadUserType (array, required)
Filters which types of road users receive the message.
-
Valid values:
"Vehicle","VulnerableRoadUser""Vehicle": Vehicles with a metal box (Car, Truck, Bus, etc.)"VulnerableRoadUser": Road users without protective housing (Pedestrian, Cyclist, Motorcyclist, etc.)
-
Minimum: 1 item, Maximum: 2 items
-
Example:
"roadUserType": ["Vehicle", "VulnerableRoadUser"]
triggerConditions (array, required)
Defines when the message is triggered relative to the geofence.
-
Valid values:
"enter","leave","inside","crossing" -
At least one trigger condition must be specified
-
Example:
"triggerConditions": ["enter", "inside"] -
See Trigger Conditions section for detailed explanation
limits (object, optional)
Speed and heading constraints for message triggering.
The limits object contains speed and/or heading constraints:
-
speed: Defines acceptable speed range. Messages trigger when road user speed is OUTSIDE this range (either too slow OR too fast). Containsminandmaxvalues in m/s (0-160). -
heading: Filters messages by direction of travel. Messages trigger only when road user heading falls within this range. Containsminandmaxvalues in degrees (0-360).
Example:
"limits": [{
"speed": {"min": 10, "max": 20},
"heading": {"min": 45, "max": 135}
}]See Speed Limits and Heading/Direction Limits sections for detailed examples.
distributionType (array, optional)
How the message is distributed to recipients.
-
Valid values:
"Targeted","Broadcast" -
Defaults to
["Targeted"]if not specified -
Example:
"distributionType": ["Targeted"] -
See Distribution Types section for details
distributionSchedule (object, optional)
Controls message repetition and timing.
-
repeatPeriod: Seconds between message publications (minimum 5 seconds) -
duration: Total duration in minutes -
startTime: ISO 8601 UTC timestamp for scheduled start (must end withZ) -
Example:
"distributionSchedule": {
"repeatPeriod": 30,
"duration": 3600,
"startTime": "2024-06-15T12:00:00Z"
}Note: Requirements for distributionSchedule vary by distribution type. See Validation Rules for details on when this field is required vs. optional.
Message Types
In addition to the common message fields above, each message must include exactly one of the following message type objects:
generic: Custom V2X messages (TAM, EVA, vendor-specific)saeAlert: SAE J2735 Road Side Alert (RSA)saeInfo: SAE J2735 Traveler Information Message (TIM)etsiAlert: ETSI Decentralized Environmental Notification Message (DENM)
Generic Custom Messages
Generic messages allow you to send any custom V2X message format, including standard messages not natively supported by the API (TAM, EVA, etc.) or vendor-specific custom messages.
Required Fields:
messageType: String identifying the message type (e.g., "BSM", "PSM", "TAM", "EVA", "VendorCustom")messageFormat: Encoding format (e.g., "j2735", "j2735_gr", "protobuf", "json")payload: Base64-encoded message content
Important: ETX prefers j2735 or j2735_gr encoding for standard V2X messages. Only vendor-specific message types should use alternative formats like JSON.
Custom Message Examples
Example 1: Simple JSON Custom Message
Use Case: Send a custom vendor-specific warning in JSON format.
Original JSON Message:
{
"warning": "Construction ahead",
"severity": "high",
"distance": 500,
"speed_limit": 45
}Step-by-Step Encoding:
# Step 1: Create your JSON message
echo '{"warning":"Construction ahead","severity":"high","distance":500,"speed_limit":45}' > message.json
# Step 2: Encode to base64
base64 message.json
# Result: eyJ3YXJuaW5nIjoiQ29uc3RydWN0aW9uIGFoZWFkIiwic2V2ZXJpdHkiOiJoaWdoIiwiZGlzdGFuY2UiOjUwMCwic3BlZWRfbGltaXQiOjQ1fQo=Configuration:
{
"isPrivate": true,
"roadUserType": ["Vehicle"],
"triggerConditions": ["enter"],
"distributionType": ["Targeted"],
"generic": {
"messageType": "VendorWarning",
"messageFormat": "json",
"payload": "eyJ3YXJuaW5nIjoiQ29uc3RydWN0aW9uIGFoZWFkIiwic2V2ZXJpdHkiOiJoaWdoIiwiZGlzdGFuY2UiOjUwMCwic3BlZWRfbGltaXQiOjQ1fQo="
}
}Client-Side Decoding:
// Receive message via MQTT
const base64Payload = message.payload;
// Decode base64 to string
const jsonString = atob(base64Payload);
// Parse JSON
const customMessage = JSON.parse(jsonString);
console.log(customMessage.warning); // "Construction ahead"
console.log(customMessage.severity); // "high"Example 2: TAM (TollAdvertisementMessage)
Use Case: Broadcast toll pricing and collection point information to vehicles approaching tolled road segments or express lanes.
TAM Message Structure (SAE J3217):
TollAdvertisementMessage ::= SEQUENCE {
tollChargesTable TollChargesTable,
tollAdvInfo TollAdvertisementInfo OPTIONAL,
...
}
TollAdvertisementInfo ::= SEQUENCE {
tamSequenceNum MsgCount,
totalTams INTEGER (1..10, ...),
tamNum INTEGER (1..10, ...),
tollChargerInfo TollChargerInfo,
timestamp DDateTime,
tumInstructions TumInstructions OPTIONAL,
tollPointMap TollPointMap,
tumPublicKey OCTET STRING (SIZE(32)),
ackPolicy AckPolicy,
lastTollPtDataReq BOOLEAN OPTIONAL,
...
}Important: The message structure shown above is provided as an example for illustration purposes. Always refer to the most current version of the SAE J3217 standard when creating, encoding, and decoding TollAdvertisementMessage. Message definitions, field requirements, and data types may change with standard updates.
Step-by-Step Process:
Create TAM message using ASN.1 encoder:
# Using asn1tools or similar library
import asn1tools
import base64
# Load SAE J3217 schema
j3217 = asn1tools.compile_files(['SAE-J3217.asn'])
# Create TAM message (SAE J3217)
tam_message = {
'tollChargesTable': {
'tollCharges': [
{
'tollPointId': 1001,
'tollLaneSet': [1, 2, 3], # Lane IDs subject to toll
'paymentFee': {
'amount': 250, # $2.50 in cents
'currency': 840 # ISO 4217 code for USD
},
'vehicleClass': 1 # Passenger vehicle
},
{
'tollPointId': 1001,
'tollLaneSet': [1, 2, 3],
'paymentFee': {
'amount': 750, # $7.50 in cents
'currency': 840
},
'vehicleClass': 2 # Commercial vehicle
}
]
},
'tollAdvInfo': {
'tamSequenceNum': 1,
'totalTams': 1,
'tamNum': 1,
'tollChargerInfo': {
'tollChargerId': 5001,
'tollPointId': 1001
},
'timestamp': {
'year': 2024,
'month': 3,
'day': 15,
'hour': 14,
'minute': 30
},
'tollPointMap': {
'tollPoints': [
{
'tollPointId': 1001,
'position': {
'lat': 385447190, # Latitude * 10^7
'lon': -771407890 # Longitude * 10^7
}
}
]
},
'tumPublicKey': b'\x04' + b'\x00' * 31, # 32-byte public key
'ackPolicy': 0 # No acknowledgment required
}
}
# Encode to UPER (Unaligned Packed Encoding Rules)
tam_bytes = j3217.encode('TollAdvertisementMessage', tam_message, 'uper')
# Encode to base64 for API
tam_base64 = base64.b64encode(tam_bytes).decode('utf-8')
print(tam_base64)
# Result: AQEyNFZ4AAHgQA...Configuration:
{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["inside"],
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 60,
"duration": 480
},
"generic": {
"messageType": "TAM",
"messageFormat": "j3217",
"payload": "AQEyNFZ4AAHgQAIAAAEBZAAAAAEyAAAA..."
}
}Why Use Generic for TAM:
- TAM is not natively supported as a field in the API (only RSA, TIM, DENM)
- Must be sent as generic message with proper encoding
- Message type "TAM" allows receivers to identify and parse correctly
Example 3: EVA (Emergency Vehicle Alert)
Use Case: Alert road users when emergency vehicle is approaching the geofence area.
EVA Message Structure (SAE J2735):
EmergencyVehicleAlert ::= SEQUENCE {
timeStamp MinuteOfTheYear OPTIONAL,
id TemporaryID,
rsaMsg RoadSideAlert,
responseType ResponseType OPTIONAL,
details EmergencyDetails,
...
}Important: The message structure shown above is provided as an example for illustration purposes. Always refer to the most current version of the SAE J2735 standard when creating, encoding, and decoding EmergencyVehicleAlert. Message definitions, field requirements, and data types may change with standard updates.
Step-by-Step Process:
Create EVA message:
import asn1tools
import base64
j2735 = asn1tools.compile_files(['SAE-J2735.asn'])
# Create EVA message
eva_message = {
'timeStamp': 234567,
'id': b'\xAB\xCD\xEF\x01',
'rsaMsg': {
'msgCnt': 5,
'typeEvent': 9729, # Emergency vehicle
'description': [9730, 9731]
},
'responseType': 1, # Emergency
'details': {
'eventType': 3, # Fire truck
'responseType': 1, # Code 3 (lights and sirens)
'sirenUse': 1, # Siren active
'lightsUse': 1 # Lights active
}
}
# Encode to UPER
eva_bytes = j2735.encode('EmergencyVehicleAlert', eva_message, 'uper')
# Encode to base64
eva_base64 = base64.b64encode(eva_bytes).decode('utf-8')Configuration:
{
"isPrivate": false,
"roadUserType": ["Vehicle", "VulnerableRoadUser"],
"triggerConditions": ["inside"],
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 5,
"duration": 60
},
"generic": {
"messageType": "EVA",
"messageFormat": "j2735",
"payload": "AwOrzwEABSYBJgImAwEBCgEBAQ=="
}
}Why Use Generic for EVA:
- EVA is part of SAE J2735 but not natively supported as API field
- Requires UPER encoding of the complete message structure
- Broadcast distribution ensures all nearby vehicles receive alert
Example 4: J2735_gr (GeoRouted) Custom Message
Use Case: Send vendor-specific message wrapped in GeoRoutedMsg protocol buffer.
GeoRoutedMsg Structure:
message GeoRoutedMsg {
bytes msgBytes = 1; // Your actual message
google.protobuf.Timestamp time = 2; // Timestamp
optional Position position = 3; // GPS position
}
message Position {
double latitude = 1;
double longitude = 2;
}Create your custom message:
import base64
from google.protobuf.timestamp_pb2 import Timestamp
from datetime import datetime
# Your custom message (already encoded as bytes)
custom_msg_bytes = b'\x01\x02\x03\x04...' # Your message content
# Create GeoRoutedMsg
geo_msg = GeoRoutedMsg()
geo_msg.msgBytes = custom_msg_bytes
geo_msg.time.GetCurrentTime()
geo_msg.position.latitude = 38.8977
geo_msg.position.longitude = -77.0366
# Serialize to bytes
geo_bytes = geo_msg.SerializeToString()
# Encode to base64
geo_base64 = base64.b64encode(geo_bytes).decode('utf-8')Configuration:
{
"isPrivate": true,
"roadUserType": ["Vehicle"],
"triggerConditions": ["enter"],
"distributionType": ["Targeted"],
"generic": {
"messageType": "CustomVendorMessage",
"messageFormat": "j2735_gr",
"payload": "CgQBAgMEEg4I4/fA..."
}
}When to Use j2735_gr:
- Message needs geographic routing information
- Want to include precise timestamp and position
- Using GeoRelevance MQTT topics (requires GeoRoutedMsg wrapper)
Custom Message Payload Encoding Reference
Encoding Process Summary:
Step 1: Client - Create Message
├─ JSON: Write JSON object
└─ Custom: Encode based on message format
Step 2: Client - Encode to Base64
├─ Input: Raw bytes from Step 1
├─ Process: base64.b64encode()
└─ Output: Base64 string
Step 3: Client - Submit Configuration to API
├─ Set messageType (identifies message, e.g., "CustomMsg", "RSA")
├─ Set messageFormat (encoding type, e.g., "j2735", "protobuf")
└─ Set payload (base64 string)
Step 4: Server - Process Configuration
├─ Base64 decode payload to raw bytes
├─ Publish raw bytes to MQTT broker (no wrapping for generic messages)
└─ Note: SAE/ETSI standard messages are wrapped in GeoRoutedMsg protobuf
Step 5: Client - Receive and Process
├─ Subscribe to MQTT topic
├─ Receive raw bytes
├─ Parse based on messageFormat
└─ Process message contentCommon Tools for Encoding:
# Command line base64
echo -n "your message" | base64
# Python
import base64
base64.b64encode(b"your message").decode('utf-8')
# JavaScript/Node.js
Buffer.from("your message").toString('base64')
# Java
Base64.getEncoder().encodeToString("your message".getBytes())Message Format Guidelines:
| Format | Use Case | Encoding | Preferred For |
|---|---|---|---|
j2735 | SAE standard messages | ASN.1 UPER (pre-encoded) | EVA, standard V2X |
j3217 | C-V2X toll messages | ASN.1 UPER (pre-encoded) | TAM (Toll Advertisement) |
j2735_gr | Pre-encoded geo-routed messages | ASN.1 UPER (pre-encoded) | Pre-encoded UPER messages |
json | Vendor custom data | JSON + Base64 | Simple custom alerts |
protobuf | Structured custom messages | Protocol Buffers | High-performance custom |
Note: For generic custom messages, all formats refer to pre-encoded payloads. The j2735_gr suffix indicates the message format, not that ETX will add GeoRoutedMsg wrapping (generic messages are published as-is).
Message Publishing Behavior:
| Message Type | Payload Processing | GeoRoutedMsg Wrapper | Position Data | Use Case |
|---|---|---|---|---|
| Generic (custom) | Published as raw bytes (as-is) | ❌ NO | ❌ NO | Pre-encoded vendor messages |
| SAE (RSA/TIM) | JSON → UPER encoding | ✅ YES | ✅ YES | Standard SAE messages |
| ETSI (DENM) | JSON → UPER encoding | ✅ YES | ✅ YES | Standard ETSI messages |
Critical Distinction: Generic custom messages are published as raw bytes without any wrapper. If your use case requires position data or GeoRoutedMsg wrapping, you must include it in your pre-encoded payload, or use the standard SAE/ETSI message types which are automatically wrapped.
Important Notes:
- Always validate your encoded message can be decoded before deployment
- Test with actual V2X receivers to ensure compatibility
- ETX system does NOT validate message content (only base64 format)
- Clients are responsible for parsing and validating message semantics
- Use Public vendorId for interoperable messages, Direct vendorId for proprietary formats
- Base64 decoding happens server-side - clients receive already-decoded raw bytes via MQTT
- Generic messages are published exactly as provided (no encoding, no wrapping, no position)
SAE Road Side Alert (RSA)
RSA messages send alerts for nearby hazards to travelers, as defined in SAE J2735 standard.
Required Fields:
typeEvent: ITIS code describing the alert/danger/hazard (integer 0-65535)description: Optional array of additional ITIS codes (up to 8 items)msgCnt: Optional message counter (0-127, auto-populated if omitted)
Example:
{
"isPrivate": false,
"roadUserType": ["Vehicle", "VulnerableRoadUser"],
"triggerConditions": ["enter"],
"distributionType": ["Targeted"],
"saeAlert": {
"msgCnt": 0,
"typeEvent": 521,
"description": [522, 523]
}
}ITIS Codes: Complete set available in Volume Two of SAE J2540 standard.
Common ITIS Event Codes:
- 521: Accident
- 522: Multi-vehicle accident
- 771: Road construction
- 1025: Severe weather
Important: Always refer to the most current versions of the SAE J2735 and SAE J2540 standards when implementing RSA messages. ITIS codes, message field requirements, and encoding specifications may change with standard updates. Verify your implementation against the latest published standards.
Message Standard: Must use "messageStandard": "sae" in configuration.
SAE Traveler Information Message (TIM)
TIM messages send advisory and road sign information to equipped devices.
Required Fields for saeInfo:
dataFrames (array, required) - Array of data frames (1-8 items). Each data frame contains:
-
frameType: Type of frame - "unknown", "advisory", "roadSignage", or "commercialSignage" -
msgId: Message identifier object containing either:furtherInfoID: 4-character hexadecimal string (for advisory frame types)roadSignID: Object with position (lat/long) and viewAngle (for roadSignage frame types)
-
startTime: Elapsed minutes of current year (0-527040) -
durationTime: Duration in minutes (0-32000, where 32000 = forever) -
priority: Importance level (0-7, where 7 is most important) -
regions: Array of geographic paths (1-16 items). Auto-populated from geofence if not specified -
content: Content object, must be one of:advisory: Array of ITIS codes and text itemsworkZone: Array of work zone signs and directionsgenericSign: Array of MUTCD signs and directionsspeedLimit: Array of speed limits and cautionsexitService: Array of roadside available services
Optional Fields for saeInfo:
msgCnt: Message counter (0-127, auto-populated if omitted)timeStamp: Elapsed minutes of current year (0-527040)packetID: Unique packet identifier (18-character hex string)urlB: Base URL for additional information (max 45 characters)
Optional Fields for DataFrame:
startYear: Year according to Gregorian calendar (0-4095, where 0 = unknown)contentNew: Extended content for future entities (e.g., friction information)
Example:
{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["inside"],
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 30,
"duration": 60,
"startTime": "2024-06-15T12:00:00Z"
},
"saeInfo": {
"msgCnt": 5,
"timeStamp": 100000,
"packetID": "B343B343B343B343A5",
"urlB": "http://example.com",
"dataFrames": [{
"frameType": "advisory",
"msgId": {
"furtherInfoID": "1101"
},
"startYear": 2024,
"startTime": 100000,
"durationTime": 120,
"priority": 5,
"regions": [{
"description": {
"path": {
"offset": {
"ll": {
"nodes": [
{
"delta": {
"node-LatLon": {
"lon": -771496500,
"lat": 389568100
}
}
},
{
"delta": {
"node-LatLon": {
"lon": -771495000,
"lat": 389569000
}
}
}
]
}
}
}
}
}],
"content": {
"advisory": [
{"item": {"itis": 8960}},
{"item": {"text": "Road Work Ahead"}}
]
}
}]
}
}Message Standard: Must use "messageStandard": "sae" in configuration.
Note on Regions: The regions field in each DataFrame is required and defines the geographic area where the message applies. While you can explicitly specify regions using SAE J2735 GeographicalPath format (as shown in the example above with lat/lon node arrays), the system can automatically populate this field from your geofence geometry if you omit it, converting it to the proper format.
Important Limitation: When the system auto-populates regions from your geofence, it only supports LineString and Polygon geometries. Circle regions are not supported in the automatic conversion process because the API currently only supports line strings and polygons. If you need to define circular regions, you must explicitly add them to the regions field in your payload using the SAE J2735 GeographicalPath format with appropriate node coordinates.
Important: Always refer to the most current version of the SAE J2735 standard when implementing TIM messages. Message field requirements, DataFrame structures, content types, and encoding specifications may change with standard updates. Verify your implementation against the latest published standards.
ETSI Decentralized Environmental Notification Message (DENM)
DENM messages alert road users of detected events using ITS communication technologies, as defined in ETSI standards.
Required Fields:
header (object, required)
-
protocolVersion: Must be 2 -
messageId: Must be 1 (for DENM) -
stationId: Station identifier (uint32)
denm (object, required)
-
management: Management container with event metadata -
management.actionId: Originating station ID and sequence number -
management.detectionTime: Timestamp in milliseconds since start of 2004 -
management.referenceTime: Timestamp in milliseconds since start of 2004 -
management.eventPosition: Latitude, longitude, altitude, confidence ellipse -
management.stationType: Type of ITS station (0-255) -
situation: Optional situation container -
situation.informationQuality: Quality level (0-7) -
situation.eventType: Cause and sub-cause codes
Example:
{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["enter"],
"distributionType": ["Targeted"],
"etsiAlert": {
"header": {
"protocolVersion": 2,
"messageId": 1,
"stationId": 12345
},
"denm": {
"management": {
"actionId": {
"originatingStationId": 12345,
"sequenceNumber": 1
},
"detectionTime": 123456789,
"referenceTime": 123456789,
"eventPosition": {
"latitude": 388977000,
"longitude": -770366000,
"positionConfidenceEllipse": {
"semiMajorConfidence": 100,
"semiMinorConfidence": 50,
"semiMajorOrientation": 0
},
"altitude": {
"altitudeValue": 10000,
"altitudeConfidence": "alt-010-00"
}
},
"stationType": 15
},
"situation": {
"informationQuality": 5,
"eventType": {
"ccAndScc": {
"trafficCondition1": 5
}
}
}
}
}
}Message Standard: Must use "messageStandard": "etsi" in configuration.
Station Types (stationType):
- 0: unknown
- 1: pedestrian
- 5: passengerCar
- 6: bus
- 15: roadSideUnit
Cause Codes (eventType):
- Traffic Condition (1): trafficCondition1 with sub-cause 0-255
- Accident (2): accident2 with sub-cause 0-255
- Roadworks (3): roadworks3 with sub-cause 0-255
- Impassability (5): impassability5 with sub-cause 0-255
- Wrong Way Driving (14): wrongWayDriving14 with sub-cause 0-255
- Emergency Vehicle Approaching (95): emergencyVehicleApproaching95 with sub-cause 0-255
Important: Always refer to the most current ETSI standards (ETSI EN 302 637-3) when implementing DENM messages. Message field requirements, station types, cause codes, and encoding specifications may change with standard updates. Verify your implementation against the latest published ETSI standards.
Message Standards
When creating a configuration, specify the V2X message standard:
{
"messageStandard": "sae"
}Options:
"sae"- SAE J2735 (North American) standard (default)"etsi"- ETSI (European) standard
Validation Rules:
- If using
saeAlertorsaeInfo, must specify"messageStandard": "sae"(or omit for default) - If using
etsiAlert, must specify"messageStandard": "etsi" - Generic messages can use either standard
Advanced Configuration Options
Speed Limits
Speed limits define an acceptable speed range for road users. Messages are triggered when the road user's speed falls outside this range (either too slow OR too fast) AND the trigger conditions are met.
Fields:
min: Minimum required speed in m/s (0-160)max: Maximum acceptable speed in m/s (0-160)- Constraint:
max >= min
Example:
{
"limits": [{
"speed": {
"min": 10,
"max": 20
}
}]
}Behavior: Message sends if road user speed is:
- Below 10 m/s (too slow), OR
- Above 20 m/s (too fast)
Use Cases:
- School zone warnings for speeding vehicles
- Work zone alerts for vehicles exceeding speed limits
- Slow-moving vehicle warnings in high-speed areas
Speed Conversion:
- 1 m/s = 3.6 km/h = 2.237 mph
- 25 mph ≈ 11.18 m/s
- 55 mph ≈ 24.59 m/s
- 100 km/h ≈ 27.78 m/s
Heading/Direction Limits
Heading limits filter messages based on the road user's direction of travel (0-360 degrees).
Fields:
min: Minimum heading in degrees (0-360)max: Maximum heading in degrees (0-360)
Example:
{
"limits": [{
"heading": {
"min": 45,
"max": 135
}
}]
}Behavior: Message sends if road user heading is between 45° and 135° (generally eastbound).
Special Case - Wrap Around:
If min > max, the system handles wrap-around for directions near north:
{
"heading": {
"min": 350,
"max": 10
}
}This captures headings from 350° to 360° (clockwise) and 0° to 10° (continuing clockwise), representing ±10° around north.
Heading Reference:
- 0° = North
- 90° = East
- 180° = South
- 270° = West
Use Cases:
- Wrong-way driver alerts (heading opposite to expected direction)
- Lane-specific warnings (e.g., only for northbound traffic)
- Directional construction zone alerts
Road User Types
Specify which types of road users should receive the message:
Options:
"Vehicle"- Vehicles with protective housing (cars, trucks, buses)"VulnerableRoadUser"- Road users without protective housing (pedestrians, cyclists, motorcyclists)
Rules:
- Must specify 1 or 2 types
- Cannot specify the same type twice
Examples:
{
"roadUserType": ["Vehicle"]
}{
"roadUserType": ["Vehicle", "VulnerableRoadUser"]
}Use Cases:
- Pedestrian crossing warnings for vehicles only
- Bike lane alerts for vulnerable road users only
- General hazard warnings for all road users
Distribution Types
Distribution types control how and where messages are delivered to road users through MQTT topics. Understanding the difference between Targeted and Broadcast distribution is critical for proper system integration.
Understanding Distribution Types:
Key Concept: The distribution type determines which MQTT topic namespace is used:
- Targeted → Messages sent to Direct MQTT topics
- Broadcast → Messages sent to Regional MQTT topics
Targeted Distribution
Targeted distribution sends messages directly to specific road users who trigger the geofence conditions. The system evaluates geofence violations in real-time and generates personalized messages for affected road users.
How It Works:
- Road user enters/exits/crosses geofence or meets trigger conditions
- System evaluates speed/heading limits if defined
- Message is generated and sent to that specific user's Direct MQTT topic
- Only the triggered road user receives the message
MQTT Topic Structure:
vzimp/1/Direct/{clientType}/{clientSubtype}/{vendorId}/{messageFormat}/{messageType}/{sessionID}Example Subscription for Targeted Messages:
# Subscribe to all RSA messages for your vehicle
vzimp/1/Direct/Vehicle/PassengerCar/YourVendorID|Public/j2735_gr/RSA/+
# Subscribe to all TIM messages for your vendor
vzimp/1/Direct/+/+/YourVendorID/j2735_gr/TIM/+
# Subscribe to all TIM messages Public vendor
vzimp/1/Direct/+/+/Public/j2735_gr/TIM/+
# Subscribe to all targeted messages (any type)
vzimp/1/Direct/+/+/+/+/+/+Characteristics:
- Delivery: Unicast (one-to-one) to specific session
- Latency: Real-time, immediate upon trigger
- Overhead: Low message volume
- Schedule: Uses
repeatPeriodonly (default 5 seconds) - Duration/StartTime: Ignored for targeted messages
- Use for: Real-time personalized warnings
Configuration Example:
{
"distributionType": ["Targeted"]
}When to Use Targeted Distribution:
- ✅ Speed limit violations (message only for speeding vehicles)
- ✅ Enter/leave zone notifications (personalized alerts)
- ✅ Wrong-way driver warnings (only for violating vehicle)
- ✅ Personalized safety alerts
- ✅ Client-specific instructions
- ✅ Low latency requirements
- ✅ Minimize message overhead
Important Notes:
- Client must be connected to MQTT to receive targeted messages
- Messages are not persisted (if client disconnects, messages are lost)
- Requires active position reporting from road users
- Default repeat period: 5 seconds
- Best for dynamic, event-driven alerts
Broadcast Distribution
Broadcast distribution sends messages to geographic regions defined by 7-digit geohashes that intersect with your geofence. All road users in those regions can receive the messages.
How It Works:
- System calculates all 7-digit geohashes covered by your geofence
- Messages are broadcast to Regional MQTT topics for each geohash
- Messages are sent according to distribution schedule (repeatPeriod, duration, startTime)
- All subscribers to those geohash regions receive the messages
Coverage/Broadcast Area Calculation
When you create a Broadcast configuration, the system calculates which 7-digit geohashes are affected by your geofence. Here's how it works:
Geohash Grid System
A Geohash is a geocoding system that encodes geographic coordinates into a short string of letters and digits. Each character in the geohash represents increased precision, dividing the world into a hierarchical grid.
You can calculate geohashes for specific coordinates using this Geohash Calculator tool by providing latitude, longitude, and desired precision.
| Precision | Coverage Area | Use Case |
|---|---|---|
| 6-digit | ~1.2km × 0.6km | Large area |
| 7-digit | ~153m × 153m | ETX broadcast level |
| 8-digit | ~38m × 19m | Fine-grained |
Example: Geofence Coverage Calculation
Your Polygon Geofence:
Step 1: System Calculates Overlapping Geohashes
Step 2: Add Buffer Zone (Neighboring geohashes)
Step 3: Broadcast to Regional Topics
Coverage Area Size
Maximum Coverage Limit:
- 288 geohashes at precision 7 (approximately 6.5 km²) - a 3×3 grid of 6-digit geohashes
- If exceeded, split into multiple configurations
Coverage Estimation:
Small Intersection: 4-6 geohashes
Work Zone: 10-20 geohashes
Highway Zone: 50-100 geohashes
Maximum Allowed: 288 geohashes at 7-digit precisionPerformance Considerations
Broadcast Message Volume:
Calculation:
- Geohashes affected: N
- Repeat period: R seconds
- Duration: D minutes
- Total messages: N × (D × 60 / R)
Example:
- 20 geohashes
- 30 second repeat period
- 120 minute duration
- Total: 20 × (120 × 60 / 30) = 20 × 240 = 4,800 messages
Use Targeted if possible to reduce network overhead!MQTT Topic Structure:
vzimp/1/Regional/{geohash}/{clientType}/{clientSubtype}/{vendorId}/{messageFormat}/{messageType}/{sessionID}Geohash Format: Slash-delimited 8 characters (e.g., d/j/z/f/u/4/k/g)
Example Subscription for Broadcast Messages:
# Subscribe to RSA messages in specific 7-digit geohash
vzimp/1/Regional/d/j/z/f/u/4/k/+/+/+/Public/j2735_gr/RSA/+
# Subscribe to all messages in 7-digit geohash (all 32 8-digit sub-regions)
vzimp/1/Regional/d/j/z/f/u/4/k/+/+/+/+/+/+/+
# Subscribe to TIM messages in 6-digit geohash area (wider area)
vzimp/1/Regional/d/j/z/f/u/4/+/+/+/+/Public/j2735_gr/TIM/+
# Wide-area subscription (7-digit level only, not sub-geohashes)
vzimp/1/Regional/d/j/z/f/u/4/k/-/+/+/Public/+/+/+Characteristics:
- Delivery: Multicast (one-to-many) to geographic regions
- Latency: Scheduled transmission
- Overhead: Higher message volume (sent to all geohashes in area)
- Schedule: Requires full
distributionSchedule(repeatPeriod, duration, startTime optional) - Use for: Area-wide information and persistent warnings
- Geohash Precision: 7-digit geohashes (approximately 150m x 150m)
Configuration Example:
{
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 60,
"duration": 120,
"startTime": "2024-06-15T12:00:00Z"
}
}Distribution Schedule Fields:
repeatPeriod (integer, required) - How often to send messages in seconds (5-3600)
- Example: 30 = send message every 30 seconds
duration (integer, required) - How long to continue sending in minutes (1-32000)
-
32000 minutes ≈ 22 days = maximum duration
-
Example: 120 = continue broadcasting for 2 hours
startTime (string, optional) - ISO 8601 UTC timestamp when to start (must end with Z)
-
If omitted: broadcasting starts immediately
-
Example: "2024-06-15T07:00:00Z" = start at 7 AM UTC on June 15, 2024
-
Format:
YYYY-MM-DDTHH:MM:SSZ(theZsuffix indicates UTC timezone)
When to Use Broadcast Distribution:
- ✅ Construction/work zones (everyone in area needs to know)
- ✅ Weather warnings (affects all road users in region)
- ✅ Road closures (area-wide impact)
- ✅ Persistent hazards (debris, flooding)
- ✅ Traffic advisories
- ✅ Physical RSU (pRSU) support
Important Notes:
- Messages are broadcast to all 7-digit geohashes that intersect your geofence
- System automatically includes 1 extra geohash buffer around geofence to avoid gaps
- Subscribers receive messages based on their location/geohash subscription
- Higher network overhead (messages sent repeatedly to regions)
- Best for persistent, area-wide information
Hybrid Distribution (Targeted + Broadcast)
You can enable both distribution types simultaneously for comprehensive coverage:
{
"distributionType": ["Targeted", "Broadcast"],
"distributionSchedule": {
"repeatPeriod": 30,
"duration": 60
}
}How It Works:
- Targeted component: Sends real-time personalized messages to road users who trigger geofence
- Broadcast component: Sends scheduled messages to all Regional topics for geohash regions
When to Use Both:
- ✅ Maximum coverage (reach both position-reporting and non-reporting vehicles)
- ✅ Redundancy (ensure message delivery through multiple channels)
- ✅ Support diverse client implementations (some monitor Direct, others monitor Regional)
- ✅ Physical RSU + cloud-based processing
- ✅ Critical safety messages requiring guaranteed delivery
Example Scenario: School zone safety warning:
- Targeted: Immediate alert when vehicle enters zone while speeding
- Broadcast: Continuous advisory to all vehicles approaching the area
Choosing the Right Distribution Type
| Scenario | Recommended Type | Reason |
|---|---|---|
| Speed violation in work zone | Targeted | Only speeding vehicles need warning |
| Construction zone advisory | Broadcast | All vehicles in area need information |
| Wrong-way driver alert | Targeted | Only specific vehicle is violating |
| Weather warning (icy roads) | Broadcast | Affects entire region |
| Pedestrian crossing detection | Targeted | Alert specific approaching vehicles |
| Road closure information | Broadcast | Area-wide impact |
| Red light violation | Targeted | Specific vehicle warning |
| School zone awareness | Broadcast | All vehicles in vicinity |
| Critical intersection hazard | Both | Maximum coverage |
Validation Rules
Distribution Schedule Requirements:
For Targeted Distribution:
distributionScheduleis optional- If provided, only
repeatPeriodis used (default: 5 seconds) durationandstartTimeare ignored- Messages sent in real-time upon trigger
For Broadcast Distribution:
distributionScheduleis required- Must include both
repeatPeriodandduration startTimeis optional (defaults to immediate start)- Messages sent on schedule to all geohash regions
For Hybrid (Targeted + Broadcast):
distributionScheduleis required (for Broadcast component)- Targeted component sends immediately, Broadcast follows schedule
Distribution Type Validation:
- Cannot specify same type twice: ❌
["Broadcast", "Broadcast"] - Both types allowed: ✅
["Targeted", "Broadcast"] - If neither specified: defaults to
["Targeted"]
Message Type Considerations
TIM (Traveler Information Message) - Special Handling:
When using Broadcast distribution with TIM messages:
- System auto-converts your geofence to SAE J2735
GeographicalPathformat GeographicalPathis added to each DataFrame if not already present- Heading limits are added to
GeographicalPath/directionfield if defined - Distribution schedule parameters are added to TIM message structure
RSA (Road Side Alert):
- Works with both Targeted and Broadcast
- Broadcast: Published to all geohashes affected by geofence
- Use Public vendor ID for maximum reach
DENM (ETSI Messages):
- Follows same distribution rules as SAE messages
- Must use
messageStandard: "etsi"in configuration
Generic Custom Messages:
- Support both distribution types
- Can use vendor-specific message formats and types
Best Practices
Configuration Design
Keep Geofences Reasonably Sized: System enforces maximum 288 geohashes at precision 7. Break large areas into multiple configurations. Consider MEC coverage boundaries.
Use Appropriate Geometry Types: Use LineString/MultiLineString for crossing detection (lane boundaries, stop lines). Use Polygon/MultiPolygon for area monitoring (work zones, school zones).
Choose the Right Trigger Conditions: Use "enter" for initial warnings (entering work zone), "inside" for persistent alerts (inside school zone), "leave" for exit notifications (leaving restricted area), and "crossing" for line violations (wrong-way driving, red light).
Optimize Message Count: Maximum 10 messages per configuration. Group related messages in single configuration. Use different trigger conditions to vary timing.
Performance Optimization
Distribution Type Selection: Use "Targeted" for real-time, personalized alerts. Use "Broadcast" for persistent area-wide information. Avoid unnecessary broadcast messages (higher overhead).
Speed and Heading Limits: Only add limits when necessary for filtering. Speed limits reduce false positives. Heading limits enable directional warnings.
Configuration Activation: Set isActive: false when testing. Activate only when ready for production. Use updates to modify without recreating.
Geometry Best Practices
Polygon Winding Order: Always use counter-clockwise winding. Tools like geojson.io generate correct winding. System validates and rejects clockwise polygons.
Coordinate Precision: Use 6-7 decimal places for accuracy. 6 decimal places ≈ 0.11 meter precision. Avoid excessive precision (no benefit beyond 7 places).
Ring Closure: First and last points must be identical. System validates closure automatically. Use array copy to ensure match: [point1, point2, point3, point1].
Message Design
Private vs Public Messages: isPrivate: true makes messages only visible to your vendor's devices. isPrivate: false makes messages visible to all ETX users. Consider privacy implications.
ITIS Code Selection: Use standard ITIS codes for interoperability. Reference SAE J2540 Volume Two. Test with common V2X receivers.
Distribution Schedule Tuning: Longer repeatPeriod reduces message overhead. Shorter repeatPeriod ensures timely delivery. Balance based on urgency and area size.
Common Use Cases
Use Case 1: School Zone Speed Warning
Alert drivers entering a school zone during school hours if they're speeding.
Distribution Strategy: Use Targeted for immediate alerts to speeding vehicles.
{
"name": "Lincoln Elementary School Zone",
"description": "Speed warning for school zone during school hours",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-77.0366, 38.8977],
[-77.0360, 38.8980],
[-77.0360, 38.8970],
[-77.0366, 38.8967],
[-77.0366, 38.8977]
]]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["enter"],
"limits": [{
"speed": {
"min": 0,
"max": 11.18
}
}],
"distributionType": ["Targeted"],
"saeAlert": {
"typeEvent": 8960,
"description": [8961]
}
}],
"isActive": true
}Key Features:
- Polygon geofence around school
- "enter" trigger for initial warning
- Speed limit: 11.18 m/s (≈25 mph)
- Targeted distribution for real-time alerts
- SAE RSA message with school zone ITIS codes
MQTT Subscription (Client Side):
# Vehicle subscribes to Direct topic to receive targeted alerts
vzimp/1/Direct/Vehicle/PassengerCar/YourVendorID|Public/j2735_gr/RSA/+
How It Works:
- Vehicle enters school zone geofence
- System checks vehicle speed: if > 11.18 m/s (25 mph), trigger alert
- RSA message sent to vehicle's Direct topic:
vzimp/1/Direct/Vehicle/PassengerCar/YourVendorID/j2735_gr/RSA/{sessionID} - Only the speeding vehicle receives the alert
Use Case 2: Construction Zone Advisory
Broadcast work zone information to all vehicles approaching an intersection.
{
"name": "Main St & 5th Ave Construction",
"description": "Active road work at intersection",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-77.0400, 38.9000],
[-77.0394, 38.9003],
[-77.0394, 38.8997],
[-77.0400, 38.8994],
[-77.0400, 38.9000]
]]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle", "VulnerableRoadUser"],
"triggerConditions": ["inside"],
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 30,
"duration": 480,
"startTime": "2024-06-15T07:00:00Z"
},
"saeInfo": {
"dataFrames": [{
"frameType": "workZone",
"msgId": {
"furtherInfoID": "2001"
},
"startTime": 100000,
"durationTime": 480,
"priority": 6,
"content": {
"workZone": [
{"item": {"itis": 771}},
{"item": {"text": "Lane Closed Ahead"}}
]
}
}]
}
}],
"isActive": true
}Key Features:
- Broadcast every 30 seconds for 8 hours
- Both vehicles and vulnerable road users
- SAE TIM message with work zone content
- High priority (6) for visibility
Distribution Strategy: Use Broadcast to inform all road users in the area.
MQTT Subscription (Client Side):
# Vehicle subscribes to Regional topics based on current location
# Assuming intersection is at geohash djzfu4kg (example)
vzimp/1/Regional/d/j/z/f/u/4/k/+/+/+/Public/j2735_gr/TIM/+How It Works:
-
System calculates all 7-digit geohashes covered by intersection polygon
-
Every 30 seconds, TIM message is broadcast to Regional topics for each geohash:
vzimp/1/Regional/d/j/z/f/u/4/k/g/Software/Application/Public/j2735_gr/TIM/{sessionID}vzimp/1/Regional/d/j/z/f/u/4/k/u/Software/Application/Public/j2735_gr/TIM/{sessionID}- (and all other affected geohashes)
-
All vehicles subscribed to those Regional topics receive the work zone advisory
-
Messages continue for 8 hours (480 minutes) starting at 7 AM UTC
Use Case 3: Wrong-Way Driver Detection
Detect and alert vehicles traveling in the wrong direction on a one-way street.
{
"name": "Oak Street Wrong-Way Detection",
"description": "Alert for wrong-way drivers on one-way street",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-77.0500, 38.9100],
[-77.0494, 38.9103],
[-77.0488, 38.9106]
]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["crossing"],
"limits": [{
"heading": {
"min": 180,
"max": 360
}
}],
"distributionType": ["Targeted"],
"saeAlert": {
"typeEvent": 9729,
"description": [9730]
}
}],
"isActive": true
}Key Features:
- LineString geofence across street
- "crossing" trigger for line violation
- Heading filter: 180-360° (southbound/westbound = wrong way)
- Immediate targeted alert to wrong-way driver
- ITIS codes for wrong-way driving
Distribution Strategy: Use Targeted to alert only the violating vehicle.
MQTT Subscription (Client Side):
# Vehicle subscribes to Direct RSA messages
vzimp/1/Direct/Vehicle/+/Public/j2735_gr/RSA/+How It Works:
- Vehicle crosses LineString geofence
- System checks vehicle heading: if 180-360° (wrong direction), trigger alert
- RSA message sent immediately to vehicle's Direct topic
- Wrong-way driver receives critical safety alert
- Only the violating vehicle is alerted (not other drivers)
Use Case 4: Hybrid Distribution - Critical Intersection Hazard
Alert for a critical intersection with both real-time targeted warnings and area-wide broadcast.
Scenario: Ice storm has created hazardous conditions at a major intersection. Need to:
- Alert vehicles as they approach (Targeted)
- Provide persistent area-wide advisory (Broadcast)
{
"name": "Critical Intersection Ice Hazard",
"description": "Icy conditions at Main St & Highway 50 intersection",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-77.0550, 38.9150],
[-77.0544, 38.9153],
[-77.0544, 38.9147],
[-77.0550, 38.9144],
[-77.0550, 38.9150]
]]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle", "VulnerableRoadUser"],
"triggerConditions": ["enter"],
"distributionType": ["Targeted", "Broadcast"],
"distributionSchedule": {
"repeatPeriod": 20,
"duration": 360,
"startTime": "2024-01-15T06:00:00Z"
},
"saeAlert": {
"typeEvent": 1025,
"description": [1026, 1027]
}
}],
"isActive": true
}Key Features:
- Both Targeted and Broadcast distribution
- Immediate alerts when entering zone (Targeted)
- Persistent regional broadcasts every 20 seconds (Broadcast)
- Duration: 6 hours (360 minutes)
- Public message (isPrivate: false) for maximum reach
Distribution Strategy: Use Both for comprehensive coverage.
MQTT Subscriptions (Client Side):
For Targeted Messages:
# Subscribe to Direct RSA messages
vzimp/1/Direct/Vehicle/PassengerCar/Public/j2735_gr/RSA/+For Broadcast Messages:
# Subscribe to Regional RSA messages (update geohash based on location)
vzimp/1/Regional/d/j/z/f/u/5/5/+/+/+/Public/j2735_gr/RSA/+
vzimp/1/Regional/d/j/z/f/u/5/h/+/+/+/Public/j2735_gr/RSA/+
vzimp/1/Regional/d/j/z/f/u/5/k/+/+/+/Public/j2735_gr/RSA/+How It Works:
Targeted Component:
- Vehicle enters intersection geofence
- Immediate RSA sent to vehicle's Direct topic
- Real-time, low-latency warning
Broadcast Component:
- Every 20 seconds, RSA broadcast to all geohashes covering intersection
- Messages sent to Regional topics:
vzimp/1/Regional/{geohash}/Software/Application/Public/j2735_gr/RSA/{sessionID} - All vehicles in area receive advisory
- Continues for 6 hours or until ice clears
Benefits:
- Vehicles with active position reporting get immediate Targeted alerts
- Vehicles without position reporting still receive Broadcast messages
- Redundant delivery ensures critical safety message reaches all road users
- Supports diverse client implementations (some monitor Direct, others Regional)
Use Case 5: Mid-block Pedestrian Crossing Warning
Alert vehicles when pedestrians are crossing at a designated crosswalk.
{
"name": "Main St Crosswalk",
"description": "Pedestrian crossing detection",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[-77.0600, 38.9200],
[-77.0594, 38.9200]
]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["VulnerableRoadUser"],
"triggerConditions": ["crossing"],
"distributionType": ["Targeted"],
"saeAlert": {
"typeEvent": 8961
}
}],
"isActive": true
}Key Features:
- LineString at crosswalk location
- "crossing" trigger detects pedestrians
- Targeted to vulnerable road users
- Can be combined with vehicle warning message
Use Case 6: OEM Client-Side Logic - Broadcast Zone Definition
OEM wants vehicles to process geofence logic onboard. Send zone definition via Broadcast so vehicles can generate warnings themselves.
Scenario: Support OEM requirement to handle geofencing onboard the vehicle, or support physical RSU deployment.
{
"name": "Work Zone Definition for Client Logic",
"description": "Broadcast work zone definition for onboard processing",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-77.0800, 38.9400],
[-77.0794, 38.9403],
[-77.0794, 38.9397],
[-77.0800, 38.9394],
[-77.0800, 38.9400]
]]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["inside"],
"distributionType": ["Broadcast"],
"distributionSchedule": {
"repeatPeriod": 60,
"duration": 32000
},
"saeInfo": {
"dataFrames": [{
"frameType": "workZone",
"msgId": {"furtherInfoID": "3001"},
"startTime": 100000,
"durationTime": 32000,
"priority": 7,
"content": {
"workZone": [
{"item": {"itis": 771}},
{"item": {"text": "Active Work Zone"}}
]
}
}]
}
}],
"isActive": true
}Key Features:
- TIM message with GeographicalPath (auto-populated from geofence)
- Broadcast distribution for area-wide dissemination
- Long duration (32000 minutes ≈ 22 days)
- Regions field auto-populated with geofence converted to SAE J2735 format
Distribution Strategy: Use Broadcast to support client-side logic and pRSUs.
MQTT Subscription (Client Side):
# Vehicle subscribes to Regional TIM messages
vzimp/1/Regional/d/j/z/f/u/8/0/+/+/+/Public/j2735_gr/TIM/+How It Works:
-
System converts geofence polygon to SAE J2735 GeographicalPath
-
TIM message broadcast every 60 seconds to Regional topics for affected geohashes
-
Vehicle receives TIM with zone definition in DataFrame.regions
-
Vehicle processes GeographicalPath onboard:
- Detects when vehicle is inside the work zone
- Generates warning using onboard HMI
- No server-side evaluation needed
-
Supports pRSUs: TIM can be forwarded through physical roadside units
Use Cases:
- OEM requirement for onboard geofence processing
- Physical RSU (pRSU) deployments
- Vehicles without position reporting capability
- Regulatory compliance requiring client-side logic
Use Case 7: Multi-Zone Parking Alert
Alert drivers entering any of several restricted parking zones.
{
"name": "Downtown No Parking Zones",
"description": "Multiple restricted parking areas",
"geoFence": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[[[-77.0700, 38.9300], [-77.0694, 38.9303], [-77.0694, 38.9297], [-77.0700, 38.9294], [-77.0700, 38.9300]]],
[[[-77.0720, 38.9320], [-77.0714, 38.9323], [-77.0714, 38.9317], [-77.0720, 38.9314], [-77.0720, 38.9320]]]
]
},
"properties": {}
}]
},
"messageStandard": "sae",
"messages": [{
"isPrivate": false,
"roadUserType": ["Vehicle"],
"triggerConditions": ["enter"],
"limits": [{
"speed": {
"min": 0,
"max": 5.56
}
}],
"distributionType": ["Targeted"],
"generic": {
"messageType": "ParkingRestriction",
"messageFormat": "json",
"payload": "eyJtZXNzYWdlIjogIk5vIFBhcmtpbmcgWm9uZSJ9"
}
}],
"isActive": true
}Key Features:
- MultiPolygon for multiple zones
- Speed limit filter: only slow-moving vehicles (< 5.56 m/s ≈ 12.5 mph)
- Custom generic message for parking alert
- Triggers on entering any zone
MQTT Integration
For complete details on MQTT integration, including client connection, topic subscriptions, message publishing, and troubleshooting, please refer to the comprehensive MQTT API User Documentation.
The MQTT API documentation covers:
- Client registration and connection workflow
- Topic structure and naming conventions
- Subscription patterns for Direct, Regional, and RegionalStatic namespaces
- Message publishing to GeoRelevance topics
- Geohash calculation and dynamic subscription updates
- QoS and retain settings
- Message flow examples for Targeted and Broadcast distributions
- Debugging tips and common MQTT issues
- Best practices for robust MQTT client implementation
Troubleshooting
Common Errors and Solutions
Error: "Invalid area location"
Cause: Geofence coordinates span multiple MEC coverage areas or fall outside all MECs.
Solution:
- Ensure all coordinates are within a single MEC's geographic boundary
- Check coordinate precision and validity
- Verify coordinates are in correct order [longitude, latitude]
- Contact support if MEC boundaries are unclear
Error: "AreaSizeError"
Cause: Geofence area exceeds maximum coverage limit (288 geohashes at precision 7).
Solution:
- Reduce geofence size
- Split into multiple smaller configurations
- Remove unnecessary coordinate points
- Simplify geometry
Error: "Invalid trigger condition for geometry type"
Cause: Using incompatible trigger condition with geometry type.
Solution:
- LineString/MultiLineString: Use only "crossing"
- Polygon/MultiPolygon: Use "enter", "leave", or "inside" (not "crossing")
- Check geometry type in GeoJSON
- Verify trigger conditions array
Error: "Polygon ring not closed"
Cause: First and last coordinate points are not identical.
Solution:
// Incorrect
"coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1]]]
// Correct
"coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]Error: "Polygon ring not counter-clockwise"
Cause: Polygon coordinates are in clockwise order instead of counter-clockwise.
Solution:
- Use GeoJSON editing tools that enforce correct winding order
- Manually reverse coordinate array order
- Use geojson.io to visualize and correct
Error: "Configuration not found" (404)
Cause: Using incorrect configuration ID or configuration was deleted.
Solution:
- Verify configuration ID is correct UUID
- Use GET
/api/v1/application/configurations/geofence/idsto list all IDs - Check that configuration wasn't deleted
- Ensure using correct VendorID header
Error: "Forbidden" (403)
Cause: Authentication/authorization issue with tokens or VendorID.
Solution:
- Verify Bearer token is valid and not expired
- Verify SessionToken is valid and not expired
- Check VendorID header matches your registered vendor
- Ensure tokens have correct permissions
- Regenerate tokens if needed
Error: "Too many requests" (429)
Cause: Rate limit exceeded for API calls.
Solution:
- Implement exponential backoff retry logic
- Reduce API call frequency
- Batch operations when possible
- Contact support if limits are too restrictive
Error: "Invalid configuration" (400)
Cause: Request body doesn't conform to schema or validation rules.
Solution:
- Validate JSON syntax
- Check all required fields are present
- Verify data types match schema (strings, integers, booleans)
- Review field constraints (min/max values, string lengths, patterns)
- Use OpenAPI spec for reference
Additional Resources
- Application Configuration API Reference - API documentation
- Registration API Reference - Client registration and connection

