API reference
Everything the site does is available as JSON over HTTPS at https://cv2x.itsroads.com/api/…. The same free quota applies: 5 codec operations per day anonymously (by IP), 500 per day with a free account (session cookie).
Basics
- Requests and responses are JSON (
Content-Type: application/json). Every response hasok: trueorok: falsewith anerrorstring. - Schema: SAE J2735_202409 (1,218 ASN.1 types) plus IEEE 1609.2
Ieee1609Dot2Data. JSON conventions: SEQUENCE = object keyed by ASN.1 member names; CHOICE = object with exactly one key; SEQUENCE OF = array; ENUMERATED = name string; BIT STRING ="0101…"MSB first at the exact declared length; OCTET STRING = uppercase hex; NULL =null. - Health check:
GET /api/health→{"ok":true,"types":1218,"schema":"J2735_202409","schemas":["2024","2020","2016"]}. Quota:GET /api/quota. - Revisions: decodes captures from SAE J2735 2016, 2020 and 2024 devices (auto-detected, newest first), encodes on the current 2024 revision by default, and is built to add the 2026 revision alongside when SAE publishes it. Pass
schemato pin a revision.
Decode
Accepts hex (spaces, colons, 0x allowed), base64, XER (XML) or codec JSON. Bytes are unwrapped automatically: Ethernet II (0x88DC) → IEEE 1609.3 WSMP → IEEE 1609.2 SPDU → MessageFrame. Counts against the quota.
| Field | Type | Meaning |
|---|---|---|
data | string, required | hex / base64 / XER / JSON, up to 600 kB |
type | string | Type name. Default auto: MessageFrame, or Ieee1609Dot2Data when the bytes look like an SPDU. Setting a type disables layer peeling. |
encoding | string | uper | coer | xer; default auto (COER for Ieee1609Dot2Data, UPER otherwise) |
include_xer | bool | also return the XER text |
schema | string | J2735 revision: auto (default: newest first, falling back to older revisions until the bytes decode cleanly), 2024, 2020 or 2016 |
curl -s https://cv2x.itsroads.com/api/decode -H 'Content-Type: application/json' \
-d '{"data":"00142544A1B2C3D4…","include_xer":false}'
Response:
{
"ok": true, "input": "bytes", "type": "MessageFrame", "encoding": "uper",
"hex": "0014…", "bytes": 85, "consumed": 85,
"messageId": 20, "message": "BasicSafetyMessage", "name": "BSM — Basic Safety Message",
"json": {"messageId": 20, "value": {"BasicSafetyMessage": {"coreData": {…}}}},
"summary": {"type": "BasicSafetyMessage", "headline": "BSM from vehicle A1B2C3D4 at 15.00 m/s …",
"rows": [{"label": "Position", "value": "38.8823410, -77.1757920"}, …],
"geojson": {"type": "FeatureCollection", "features": […]} },
"layers": [{"layer": "IEEE 1609.3 WSMP", "detail": "…PSID 0x20…", "bytes": 6}, …], // when wrappers were peeled
"ieee1609dot2": {…}, // decoded SPDU when a 1609.2 wrapper was present
"trailing_bytes": 2, // only when bytes remain after the message
"xer": "<MessageFrame>…", // when include_xer
"schema": "2020", "schema_label": "SAE J2735_202007", // revision that produced the decode
"schema_note": "Decoded with SAE J2735_202007 (older revision) because …", // only when an older revision was used
"schema_attempts": ["SAE J2735_202409: decoded 80 of 85 bytes", …], // only in auto mode when the newest did not decode cleanly
"standards": {…}, "ms": 12,
"quota": {"authenticated": false, "limit": 5, "used": 1, "remaining": 4}
}Encode
Encodes codec JSON to UPER with constraint checking, then decodes it back so the response json is the canonical form. Counts against the quota.
| Field | Type | Meaning |
|---|---|---|
json | object or string, required | the message, e.g. {"messageId":19,"value":{"SPAT":{…}}} |
type | string | default MessageFrame; any schema type works |
out | string | uper (default) | coer (adds coer_hex) | xer | json |
check | bool | constraint checking, default true |
include_xer | bool | also return XER |
schema | string | J2735 revision to encode with: 2024 (default), 2020 or 2016. Response includes schema and schema_label. |
curl -s https://cv2x.itsroads.com/api/encode -H 'Content-Type: application/json' \
-d '{"json":{"messageId":20,"value":{"BasicSafetyMessage":{"coreData":{…}}}},"type":"MessageFrame","check":true}'
{"ok": true, "type": "MessageFrame", "hex": "0014…", "base64": "ABQl…", "bytes": 85, "json": {…},
"messageId": 20, "message": "BasicSafetyMessage", "name": "BSM — Basic Safety Message", "summary": {…},
"warning": "messageId 19 does not match the BasicSafetyMessage payload…", // only when inconsistent
"ms": 9, "quota": {…}}
A constraint violation returns HTTP 422 with the offending field, e.g. Constraint violation in coreData.lat: the value is outside the range….
Templates
Lists the validated example messages (id, name, messageId, type, bytes, description, standard) and packets — wrapped frame samples for the decoder. No quota.
One template with its full json, on-air hex and notes. Ids: bsm, spat, map, tim-workzone, tim-speed-limit, rsm-workzone, psm, srm, ssm, sdsm, eva, rtcm.
curl -s https://cv2x.itsroads.com/api/templates/spat | jq .template.jsonTypes
All type names in the selected revision (?schema=2024|2020|2016, default 2024: 1,218 types; 2020 and 2016: 702) plus messageIds (DSRCmsgID → MessageFrame alternative) and schemas: [{id, label, types}] for every revision installed. No quota.
curl -s https://cv2x.itsroads.com/api/types?schema=2020 | jq '.schemas, .count'Random example
A randomly generated, constraint-valid instance of any type — useful to see the exact JSON shape of a rarely used structure. Values are not meaningful. Counts against the quota.
curl -s https://cv2x.itsroads.com/api/example/RoadSafetyMessage | jq .json
curl -s "https://cv2x.itsroads.com/api/example/BasicSafetyMessage?schema=2016" | jq .json # older revisionAccounts
{"email","password","name","org"} — password ≥ 10 characters. Sets the cv2x_session HttpOnly cookie (14 days).
{"email","password"} → {"ok":true,"user":{id,email,name,org,role}} and the cookie.
Clears the cookie.
Current user (or null) and quota.
curl -s -c cookies.txt https://cv2x.itsroads.com/api/auth/login -H 'Content-Type: application/json' \
-d '{"email":"you@agency.gov","password":"…"}'
curl -s -b cookies.txt https://cv2x.itsroads.com/api/rsus
Register/login and all RSU writes check the Origin header when present; scripts without an Origin header are fine.
RSU registry (signed in)
Your devices (credentials never returned; has_auth_key etc. flags instead) and the vendor list.
Create / update. Fields: name (required), agency, vendor, model, firmware, lat, lon, elev, ip (IPv4/IPv6 literal, publicly routable on the free tier), port (161), snmp_version (3 | 2c), snmp_user, auth_proto (SHA, SHA-256, SHA-512, MD5), auth_key, priv_proto (AES, AES-256, DES), priv_key, community (v2c), mib (ntcip1218, NTCIP 1218 v01A), public (bool: coarse pin on the public map), notes. Secrets are encrypted at rest; omit them on update to keep the stored values. Up to 25 devices per account.
Removes the device and its push log.
SNMP GET of sysDescr and the RSU ID object → {"ok", "result"}.
Last 50 pushes and probes: {id, kind, msg_type, psid, params, result, ok, created}.
Push a message (NTCIP 1218)
Validates the payload as a J2735 MessageFrame, then writes one row of rsuMsgRepeatTable (store-and-repeat) or rsuIFMTable (immediate forward) over SNMPv3 authPriv.
| Field | Default | Meaning |
|---|---|---|
hex | required | UPER MessageFrame bytes |
psid | by message type | integer PSID (BSM 0x20, PSM 0x27, RTCM 0x8000, SPaT 0x8002, TIM 0x8003, MAP 0xE0000017, SSM 0xE0000015, SRM 0xE0000016, SDSM 0x8010) |
channel | 183 | C-V2X 20 MHz channel |
interval_ms | 1000 | repeat period |
priority | 6 | 0–7 |
start, end | now, +60 min | ISO-8601 UTC, e.g. 2026-10-08T14:00:00 |
row | 1 | table row index |
mode | repeat | repeat | ifm |
signed | false | RSU signs with its SCMS certificate |
curl -s -b cookies.txt https://cv2x.itsroads.com/api/rsus/12/push -H 'Content-Type: application/json' \
-d '{"hex":"001380A0…","channel":183,"interval_ms":1000,"mode":"repeat"}'
# → {"ok": true, "result": "…snmpset output…", "psid": 32770, "message": "SPAT"}Public map
RSUs whose owners opted in, with coarse (3-decimal) coordinates and no network details. No quota.
Errors, CORS and limits
- 400 bad input (not hex/base64/JSON/XER, bad JSON); 401 sign in required; 403 origin not allowed; 404 not found; 422 codec/constraint error with a descriptive message; 429 daily quota reached.
- CORS: browser calls are allowed from itsroads.com, www.itsroads.com, atosinc.com and this origin, with credentials. Server-side scripts are unaffected. The embeddable widget (
/static/cv2x-embed.js) uses this to decode on itsroads.com pages. - Rate limits: nginx limits
/api/to 10 requests/s per IP (burst 30) in addition to the daily quota. Inputs over 256 kB are rejected by the codec; each codec call runs sandboxed with a 5 s timeout. - Terms: free for engineering use; no uptime guarantee. For production integrations, SCMS or managed RSUs, contact ITS Roads.