How to access the ADS data
This is a hands-on walkthrough of the TopXView REST API — the federal-facing path to Automated Driving System data. It explains the methods you use to query the data, how to page through large pulls, and gives a worked example for every data element. Everything here runs on representative sample responses — the same shapes the live API returns.
May Mobility
Toyota Sienna Autono-MaaS · ≤25 mph · 10 Hz · LiDAR + camera + radar · 6 cameras.
Nissan · I-680
Highway 65+ mph · batch upload · single camera · plus roadside infrastructure (cameras, SPaT/MAP, signals).
One REST account
All access here uses the adsdotapiuser REST credential. Secrets stay server-side — the browser never sees them.
The data elements
Each is reachable through the same REST API. Step 7 has a runnable example for each.
AV Safety Metrics is the engineered element — surrogate safety measures (TTC, TET, TIT) computed offboard by Berkeley PATH rather than recorded by a sensor. Pull it like any other element from the step 7 console.
What this walkthrough covers
Work through the steps in order, or jump around from the left.
Get connected
This walkthrough runs entirely on representative sample responses — it makes no network calls. Real data access works through a personal portal account; this step explains how that access model works and how you'll use your credentials once they're issued.
Live data requires a portal account at ads.ccta.net — this public walkthrough uses representative samples.
How access works
TopXView uses HTTP Basic Auth: a username + password ride along
(HTTPS-encrypted) with every request. Basic Auth is the only supported method — there are no API
keys. Without credentials the server answers 401 Unauthorized; that's how you know auth (not the
network) is your problem.
| Account | Purpose |
|---|---|
| adsdotapiuser | the USDOT-scoped login — the account this walkthrough documents |
Accounts are self-managed in the topXview GUI (add / modify /
delete). Permissions are all-or-nothing: an API user sees everything the API exposes. Every access is logged
server-side (T:\RestAPILogs, by date).
Using your credentials in your own tools
# curl — the -u flag is Basic Auth curl -s "https://ads.restapi.telegra-inc.com:9081/txvapi/history/getHistoryData" \ -u "adsdotapiuser:$PASSWORD" # Python requests.get(url, auth=HTTPBasicAuth("adsdotapiuser", password)) # Postman: Authorization tab -> Type: Basic Auth -> fill username + password
Quick triage: 401 = wrong or missing credentials · timeout =
you're calling the old deprecated http://…:8080/:9080 endpoints (IP-allowlisted) — switch to
https://ads.restapi.telegra-inc.com:8081/:9081. TopXView accepts Basic Auth only.
Data flow architecture
Where the data you'll query actually comes from: vehicles and roadside infrastructure feed TopXView on CCTA premises, which archives to the AWS cloud and serves the REST API this walkthrough uses. Hover any node or connection for details · click a node to focus on everything it touches.
System architecture
What is an API, really?
If you've never pulled data from a system like this, don't worry — the idea is simple. An API is just a way for one program to ask another program for something and get an answer back. No screen-scraping, no spreadsheets emailed around — you ask a precise question, you get precise data.
The one-sentence version
It's like a research desk at an archive: you hand over a slip saying what you want and which dates, the clerk fetches the matching records, and hands you back a neat stack.
Watch a request happen
Press the button. A request travels from your computer to the TopXView server, and the data comes back.
- You fill out and send a request.
- It travels over the network to the server.
- The server looks up the matching records.
- The data comes back to your computer.
- The portal shows it to you. Done!
Anatomy of a request
A request is just a short form written in JSON — a simple
text format of "label": value pairs. Click any highlighted part below to see what it means in plain English.
{
"DataType": "MotionData",
"FilterFlags": 0,
"EventFilterList": [],
"TimeFilter": {
"StartTime": "2025-11-08T18:00:00Z",
"EndTime": "2025-11-08T18:05:00Z"
},
"PagingRequest": { "PageSize": 50000, "PageIndex": 1 }
}
Good news: only one field really changes from one question to the next — DataType.
Everything else stays almost the same. Learn this shape once and you can ask for any of the seven data elements.
Access methods
The REST API centers on one request shape — a historical batch pull — plus a handful of filters
that narrow what comes back. Everything you'll do is a combination of these. Every call also carries your
username + password (HTTP Basic Auth — that's the -u in the curl examples; no API keys exist).
Step 2 covers where credentials live.
Historical data — POST getHistoryData
The workhorse. One JSON body, sent to port 9081 over HTTPS. Only the DataType
changes between elements — the rest of the shape stays the same. This is how you pull motion, objects, camera, V2X and signal data.
# POST https://ads.restapi.telegra-inc.com:9081/txvapi/history/getHistoryData { "DataType": "MotionData", // the only field that changes per element "FilterFlags": 0, // 0 = recommended (avoids 500/timeout) "EventFilterList": [], // empty unless filtering by event "TimeFilter": { "StartTime": "2025-11-08T18:00:00Z", // ISO-8601 UTC "EndTime": "2025-11-08T18:05:00Z" }, "PagingRequest": { "PageSize": 50000, "PageIndex": 1 } }
Narrowing the result — the three filters
TimeFilter.StartTime/EndTime, ISO-8601 UTC. Source ops are Pacific — add 8h. Keep windows small."DeviceIds":[19001] to limit to a single Chid. Omit it for all vehicles.getActiveEvents first. Leave FilterFlags:0 — combining filters can 500/timeout.What comes back — the response envelope
getHistoryData does not return a bare list. It wraps records so you can check
for errors and paginate. Every client follows the same rule.
{
"ErrorCode": 0,
"ErrorMessage": "",
"Response": [ /* records here */ ],
"Page": { "PageIndex":1, "PageSize":50000, "TotalPages":3 }
}- Check
ErrorCode == 0(else surfaceErrorMessage). - Records live in
Response[]. - Fallback: if there's no
Responseand the body itself is a list, use it directly. - If
Page.TotalPages > 1, page through to get everything → next step.
Paging to pull big chunks
A busy window returns far more records than one response can hold. You ask for one page at a time and walk forward until you've collected them all. Try it below — set a result size and page size, then watch the pull assemble.
Why this matters: the 200,000-record limit
The server will not hand back more than 200,000 records in a single answer — a safety limit so no one request can overwhelm it. A few minutes of object data can blow past that easily. There are two complementary ways to get everything anyway:
fetch_streaming does automatically.Ready. Each cell is one request for one page.
The paging loop
Increment PageIndex (1-based on the production HTTPS server —
PageIndex 0 returns an "OFFSET may not be negative" error) and stop when
PageIndex ≥ Page.TotalPages, or when a page comes back empty.
Rules of thumb: PageSize 50,000 max · chunk very large windows by day/week ·
MotionDetectionData (objects) is the heaviest element — page in seconds, not minutes.
Data elements — worked examples
Pick an element on the left. Each shows what the data is, a real request (JSON / curl / Python, regenerated as you edit the window), and a response with the coded fields decoded. Run it to see the embedded sample response — the same shape the live API returns.
Onboard camera video
The May Mobility vans carry six onboard cameras. TopXView keeps that footage as
compressed video frames bundled into short zip files attached to each event. A small Python tool
(extract_may_video.py) downloads the right zips, decodes the frames, and stitches them into a
normal MP4 trimmed to your time window.
How the video is stored
Each camera saves video one frame at a time. Every frame is a tiny
file ending in .bin — a single VP9-compressed image (~720×464) plus a small label: its order, its size,
and whether it's a full "key" frame. Frames arrive about 10 times a second. Roughly every 5 minutes of frames
are zipped together and attached to an event.
The names tell you everything — which vehicle, which camera, and the exact start/end time (in microseconds since 1970). Camera positions per Telegra: FL/FC/FR front left/center/right, LC left center, RC rear center, BC back center. (RC = "rear" alongside BC = "back" is Telegra's wording — if the distinction matters for your pull, confirm with them; earlier notes read RC as right-center.)
# the zip of ~5 minutes of frames <chid>_<cam>_<start_us>_<end_us>.zip # one frame inside it <chid>_<cam>_<frame_us>.bin # 1 · find the event: ReferenceId prefix = project (P2_… May, P3_… Nissan) https://ads.restapi.telegra-inc.com:8081/txvapi/status/getActiveEvents?select=EventId,StartTime,EndTime,ReferenceId # 2 · list every zip attached to that event (returns ready-to-use paths) https://ads.restapi.telegra-inc.com:8081/txvapi/status/getActiveEvents?eventId=<eventId>&select=Attachments # 3 · download each one by its listed path https://ads.restapi.telegra-inc.com:8081/evman/events/attachments/0/0/<eventId>/<zip>
What the extractor does
ReferenceId starts with your project (P2_/P3_), then list its zips with getActiveEvents?eventId=<id>&select=Attachments (event 215 → 757 zips). Keep the ones whose filename timestamps overlap your window and paste the paths straight into --zips..bin frames are decoded into a per-zip MP4 via ffmpeg.Build your extraction command
Fill these in and copy the ready-to-run command. (This builds the command — running it needs the prerequisites below and a network path to the host.)
This exact configuration was run end-to-end on 2026-07-13 (vehicle 19201, FC camera, event 215, 23:10–23:12 UTC spanning two zips): downloaded over HTTPS, decoded, stitched across the zip boundary and trimmed to a frame-accurate 2:00 MP4 — 720×464, 10 fps, 1,200 frames — showing the van's front camera on the highway. Note: if your start time is before the first zip's first frame, the video simply starts at the footage's beginning.
Ready-to-run command
Resolved attachment URLs
Prerequisites
# ffmpeg (system) + Python packages winget install ffmpeg # Windows (apt/brew on Linux/macOS) pip install requests protobuf==3.20.3 pytz # frame decoding: a verified pure-Python image_t shim ships with this repo # (scripts/may/tele_op/types/) — no PYTHONPATH setup needed. To use May's # official module instead, put ads_dashboards/data on PYTHONPATH first. # auth + endpoint are read from .env automatically (TXV_USER / TXV_PASS)
Simpler alternative: recorded AVI
If you don't specifically need the raw onboard frames, TopXView can serve recorded camera video directly as an AVI — no zips, no protobuf, no VP9 decode. Fewest moving parts.
https://ads.restapi.telegra-inc.com:8081/txvapi2/TxvApi/getStreamRecordingAvi?streamChid=<videoChid>&utcTimeStart=<unixSeconds>&length=<seconds>&flags=0
Two caveats: it keys on a video-stream Chid (different from the 192xx data Chid), and the source files live on the file system (T:\tXv_Video), not the database. Confirm host/port and the stream-Chid mapping with Telegra first.
Good to know
- ~720×464 at 10 fps. A ~12 MB zip in ≈ ~33 MB MP4 out for ~5 minutes.
- Seams may stutter — frames can drop between zips, so don't treat the MP4 as frame-accurate for timing.
- Heavy compression — plates and faces are mostly unreadable.
- Confirm the vehicle was running first (a quick MotionData pull) to avoid a wasted extraction.
Resolved 2026-07-13: the attachment-listing endpoint
(getActiveEvents?eventId=<id>&select=Attachments) and the auth transport
(HTTP Basic) are both verified working. Still open with Telegra: the stream-Chid map for the AVI path.
Verify access for every element
The harness fires one small request per element and writes a PASS / EMPTY / FAIL report you can hand to USDOT as proof of access. Run from a machine that can reach the host.
pip install requests
python scripts/verify_access.py
# known-good window (8/8 PASS on 2026-07-13):
python scripts/verify_access.py --page-size 1000 \
--start 2025-02-05T20:00:00Z --end 2025-02-05T20:10:00ZWhat a passing run looks like
| Element | Status | Records | Note |
|---|
Illustrative — real counts come from your run. EMPTY (200 but no rows in the window) is not a failure.
Codes, endpoints & devices
Endpoints
| History | POST :9081/txvapi/history/getHistoryData |
| Events | GET :8081/txvapi/status/getActiveEvents |
| Devices | GET :8081/txvapi2/TxvApi/getDeviceConfig |
Coded fields
| SignalDisplayStatus | 0 None · 1 Red · 2 Yellow · 4 Green |
| J2735 Type | 4 SPaT · 5 MAP |
| Speed | m/s → mph × 2.2369362920544 |
| RunMode | 1 Autonomous · 5 Manual (see note) |
RunMode has two candidate mappings (disengagement analysis vs. project notes). Both agree 1=Autonomous, 5=Manual; they differ elsewhere. Confirm the canonical mapping before disengagement stats reach USDOT.
Engineered measures (AvSafetyMetrics)
| TTC | <1.5 s critical · 1.5–3 s conflict |
| PET | <1 s critical · 1–2 s conflict |
| Hard braking | ≥3.0 m/s² hard · ≥4.5 m/s² severe |
Feed: DataType "AvSafetyMetrics" → TXV_AVSAFETYMETRICS_JSON_C (Berkeley PATH). Pilot batch verified 2026-07-16: 34,509 rows, 2025-02-05 18:45–19:35 UTC, TTC populated / TET·TIT null / no PET. Thresholds are the common research values; confirm program-official ones before formal reporting.
DataType → SQL table
| Element | DataType | Proj |
|---|---|---|
| Ego telemetry | MotionData | P2/P3 |
| Objects | MotionDetectionData | P2/P3 |
| Camera meta | MetadataFrame | P3 |
| SPaT/MAP | J2735Message | P3 |
| Signals | SignalDisplayStatus | P3 |
| Safety metrics | AvSafetyMetrics | P3 |
Device / Chid map
| AV_Echo (P3) | 19001 |
| May Mobility (P2) | 19200–19206 |
mallory 19200 · megalodon 19201 · morizo 19202 · mav 19203 · metatron 19204 · marymae 19205 · mastermind 19206