comma API spec
Base URL: https://api.commadotai.com/
Definitions
Dongle ID
A dongle ID is an 16-character alphanumeric device identifier. Each comma device has a unique dongle ID.
Segment
A segment is one minute of driving. openpilot rotates log and camera files at this interval. Segments are numbered in a 0-indexed fashion.
Segment names are of the form dongle_id|YYYY-MM-DD--HH-MM-SS--N
where N is the segment number. For example, 0375fdf7b1ce594d|2019-05-21--23-17-14--0
.
Route
A route is a sequence of segments recorded between car ignition and power-down. Route names are of the form dongle_id|YYYY-MM-DD--HH-MM-SS
. For example, 0375fdf7b1ce594d|2019-05-21--23-17-14
.
Authentication
Include a JWT header of the following format in order to access authenticated endpoints:
curl -H 'Authorization: JWT {{token}}' https://api.commadotai.com/
Token can be acquired at jwt.comma.ai
Enter your token here to autofill code blocks:
Response Codes
We use conventional HTTP response codes to signal success or failure of API requests.
200 - OK
400 - Bad Request: Likely due to an invalid or missing parameter.
401 - Unauthorized: JWT token invalid.
403 - Forbidden. Authenticated user lacks access to desired entity.
404 - Not Found: Requested entity does not exist.
409 - Conflict: Entity already exists.
429 - Too Many Requests: Too many requests, too quickly. Please use exponential backoff and see per-endpoint rate limit documentation.
Account
Profile
GET /v1/me/
Returns information about the authenticated user
curl https://api.commadotai.com/v1/me/ -H 'Authorization: JWT {{token}}'
{
"email": "commaphone3@gmail.com",
"id": "2e9eeac96ea4e6a6",
"points": 34933,
"regdate": 1465103707,
"superuser": false,
"username": "joeyjoejoe"
}
Response
Key | Type | Description |
---|---|---|
"email" | string | Your email |
"id" | (string) | Dongle ID |
"points" | (integer) | Number of comma points |
"regdate" | (integer) | Seconds since epoch at time of registration |
"superuser" | (bool) | Apply for superuser here |
"username" | (string) | Your username |
Devices
GET /v1/me/devices/
List devices owned or readable by authenticated user
curl https://api.commadotai.com/v1/me/devices/ -H 'Authorization: JWT {{token}}'
Response
[
{
"alias": "Comma EON",
"athena_host": "prod-comma-public-athena-0.prod-comma-public-athena.production.svc.cluster.local",
"device_type": "neo",
"dongle_id": "4bba516fb4439b31",
"ignore_uploads": null,
"is_owner": true,
"is_paired": true,
"last_athena_ping": 1644418781,
"last_gps_accuracy": 12,
"last_gps_bearing": 0,
"last_gps_lat": 32.0,
"last_gps_lng": -117.0,
"last_gps_speed": 0,
"last_gps_time": 1558583671000,
"openpilot_version": "0.8.13",
"prime": true,
"prime_type": 1,
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLI++RMXz29fBPNdECbCL8SGQ1+O/y1xhLsm/XsApxlghsKiWFSXiLJbHkHFOhQb6F421pVMZI0NtVXK5hUmwaAYLVg644/sLv/J32iW2vvdntT6GRTJxJr4LvbuXuBggW2sIYINFOOKng71CO5BxUNn+WNmeYFSqblFi4HjIuGbUZABuF9t0nkjMMVDZm9pTeeWqJtC4BxlACmJPA/88bdsiq4VDZ51yWqXxKJAq1HpG8RXpBs2leNQfnqF/mwtAkSeatqJYTjNAv77lFVg0rOQ6XjDLGdtRiloD+mNnJa1CJF4NiUG7hY/mdmolE4ML9W8YYX1aHNROmZApAt+Bn root@localhost\n",
"serial": "fa9bfe8a",
"sim_id": "890000000000000000",
"trial_claimed": false
},
{
"alias": "Toyota RAV4 EON Gold",
"athena_host": "prod-comma-public-athena-0.prod-comma-public-athena.production.svc.cluster.local",
"device_type": "neo",
"dongle_id": "b0c9d2329ad1606b",
"ignore_uploads": null,
"is_owner": false,
"is_paired": true,
"last_athena_ping": 1633318781,
"last_gps_accuracy": 10,
"last_gps_bearing": 323,
"last_gps_lat": 32.0,
"last_gps_lng": -117.0,
"last_gps_speed": 26.64,
"last_gps_time": 1558736867000,
"openpilot_version": "0.8.13",
"prime": true,
"prime_type": 2,
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUl0gKppV0TivHeL3PPqHeA2boPhKleJNdNWd5OeOhcD5N0Wsk9DLI/iBhbM1Q+LfJJsjBoJ+V/Hs9sSnIS04nuwaQMoj75gV+HwmVfBHY+UnGKCfpLpW7PCHgeReeUKOUZzTrrxp67NJaOQtdokq2oTlX4OPMzDncNJQAECnFz8DkGQMjapJVa6ctNuANaJscjlwokz4TYHlQAktb7WZoi4iRJMi6bR6HSb3R7uflrUbnS5OyebKLr6ZbhHPIy22rILXju/15XRhRPxfAjOPBXg+/WFwSBb3j6bL6TLbShXrJOsV6NrN7+Z0C3V6ZeH7SXl8Cua7FV0l7XodkDXaf root@localhost\n",
"serial": "ba9bfe7b",
"sim_id": "890000000000005462",
"trial_claimed": true
}
]
Response
JSON array of devices, sorted by key "last_athena_ping" descending
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | see Dongle ID |
"alias" | (string) | Globally unique device nickname |
"serial" | (string) | Device serial |
"athena_host" | (string) | Last connected athena server |
"last_athena_ping" | (integer) | Timestamp of last athena ping |
"ignore_uploads" | (bool) | If uploads are ignored |
"is_paired" | (bool) | Device has an owner |
"is_owner" | (bool) | Authed user has write-access to device |
"public_key" | (string) | 2048-bit public RSA key |
"prime" | (bool) | If device has prime |
"prime_type" | (integer) | Prime type: 0: no prime, 1: standard prime, 2: prime lite |
"trial_claimed" | (bool) | If device prime trial is claimed |
"device_type" | (string) | one of ("neo", "panda", "app") |
"last_gps_time" | (integer) | Milliseconds since epoch of last gps. Updates upon successful call to device location endpoint |
"last_gps_lat" | (float) | Latitude of last location |
"last_gps_lng" | (float) | Longitude of last location |
"last_gps_accuracy" | (float) | Accuracy (m) of last location |
"last_gps_speed" | (float) | Speed (m/s) at last location |
"last_gps_bearing" | (float) | Direction of last location in degrees from north |
"openpilot_version" | (string) | Last known openpilot version on device |
"sim_id" | (string) | Last known sim_id of SIM in device |
Device
Device Info
GET /v1.1/devices/:dongle_id/
Returns an object representing a comma device.
curl https://api.commadotai.com/v1.1/devices/0375fdf7b1ce594d/ -H 'Authorization: JWT {{token}}'
Response
{
"alias": "Comma EON",
"athena_host": "prod-comma-public-athena-0.prod-comma-public-athena.production.svc.cluster.local",
"device_type": "neo",
"dongle_id": "4bba516fb4439b31",
"ignore_uploads": null,
"is_owner": true,
"is_paired": true,
"last_athena_ping": 1644418781,
"last_gps_accuracy": 12,
"last_gps_bearing": 0,
"last_gps_lat": 32.0,
"last_gps_lng": -117.0,
"last_gps_speed": 0,
"last_gps_time": 1558583671000,
"openpilot_version": "0.8.13",
"prime": true,
"prime_type": 1,
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLI++RMXz29fBPNdECbCL8SGQ1+O/y1xhLsm/XsApxlghsKiWFSXiLJbHkHFOhQb6F421pVMZI0NtVXK5hUmwaAYLVg644/sLv/J32iW2vvdntT6GRTJxJr4LvbuXuBggW2sIYINFOOKng71CO5BxUNn+WNmeYFSqblFi4HjIuGbUZABuF9t0nkjMMVDZm9pTeeWqJtC4BxlACmJPA/88bdsiq4VDZ51yWqXxKJAq1HpG8RXpBs2leNQfnqF/mwtAkSeatqJYTjNAv77lFVg0rOQ6XjDLGdtRiloD+mNnJa1CJF4NiUG7hY/mdmolE4ML9W8YYX1aHNROmZApAt+Bn root@localhost\n",
"serial": "fa9bfe8a",
"sim_id": "890000000000000000",
"trial_claimed": false
}
Response
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | see Dongle ID |
"alias" | (string) | Globally unique device nickname |
"serial" | (string) | Device serial |
"athena_host" | (string) | Last connected athena server |
"last_athena_ping" | (integer) | Timestamp of last athena ping |
"ignore_uploads" | (bool) | If uploads are ignored |
"is_paired" | (bool) | Device has an owner |
"is_owner" | (bool) | Authed user has write-access to device |
"public_key" | (string) | 2048-bit public RSA key |
"prime" | (bool) | If device has prime |
"prime_type" | (integer) | Prime type: 0: no prime, 1: standard prime, 2: prime lite |
"trial_claimed" | (bool) | If device prime trial is claimed |
"device_type" | (string) | one of ("neo", "panda", "app") |
"last_gps_time" | (integer) | Milliseconds since epoch of last gps. Updates upon successful call to device location endpoint |
"last_gps_lat" | (float) | Latitude of last location |
"last_gps_lng" | (float) | Longitude of last location |
"last_gps_accuracy" | (float) | Accuracy (m) of last location |
"last_gps_speed" | (float) | Speed (m/s) at last location |
"last_gps_bearing" | (float) | Direction of last location in degrees from north |
"openpilot_version" | (string) | Last known openpilot version on device |
"sim_id" | (string) | Last known sim_id of SIM in device |
Update device properties
PATCH /v1/devices/:dongle_id/
Update device alias
alias (string): device alias shown on https://my.comma.ai and the comma connect app
curl -X PATCH 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/' \
-d '{"alias": "new_alias"}' \
-H 'Authorization: JWT {{token}}'
Response
Identical to Device Info but reflects updated fields.
Device location
GET /v1/devices/:dongle_id/location
Returns a gpsLocation
ZMQ packet from the device. The API server queries Athena and caches the location for the Device Info response.
curl 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/location' \
-H 'Authorization: JWT {{token}}'
Response
{
"dongle_id": "02ec6bea180a4d36",
"lat": 32.0,
"lng": -117.0,
"time": 1558595762000,
"speed": 0.0,
"bearing": 0.0
}
Response
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | see Dongle ID |
"lat" | (float) | Latitude, degrees |
"lng" | (float) | Longitude, degrees |
"time" | (integer) | Milliseconds since epoch |
"accuracy" | (float) | Accuracy (m) |
"speed" | (float) | Speed (m/s) |
"bearing" | (float) | Direction in degrees from north |
Pair EON
POST https://api.commadotai.com/v2/pilotpair/
Pair a comma EON to authenticated user's account.
URLEncoded Request Body
Key | Description |
---|---|
pair_token | JWT Token signed by your EON private key containing payload {"identity": <dongle-id>, "pair": true} |
curl -F 'pair_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6ImZvbyIsImlhdCI6MTU2MDU0OTM0MSwibmJmIjoxNTYwNTQ5MzQxLCJleHAiOjE1OTIwODUzNDF9.peoXbapsvT-W2dpNuHscJE6fqeaHtlB8owbTddzSkV0' https://api.commadotai.com/v2/pilotpair/ \
-H 'Authorization: JWT {{token}}'
Response
{"first_pair": true}
Response
Key | Type | Description |
---|---|---|
"first_pair" | (string) | True if the device was unpaired prior to this call. False if the device was previously paired by authenticated user. |
Unpair device
POST /v1/devices/:dongle_id/unpair
Unpair a device. Authed user must be device owner to perform. (to check ownership, see Device Info).
curl -X POST 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/unpair' \
-H 'Authorization: JWT {{token}}'
Response
{"success": 1}
Response "success" (integer): 1 if device is unpaired. 0 if device type is not one of ("neo", "panda").
Grant device read permissions to user
POST /v1/devices/:dongle_id/add_user
Grant read permissions to a user by email. Authed user must be device owner to perform. (to check ownership, see Device Info). If multiple users are attached to an email address, the device is shared with all users.
curl -X POST 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/add_user' \
-d '{"email": "mycommafriend@gmail.com"}' \
-H 'Content-Type: application/json' \
-H 'Authorization: JWT {{token}}'
Response
{"success": 1}
Remove device read permissions from user
POST /v1/devices/:dongle_id/del_user
Remove read permissions from a user by email. Authed user must be device owner to perform. (to check ownership, see Device Info). If multiple users are attached to an email address, the device removed from all users.
curl -X POST 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/del_user' \
-d '{"email": "mycommaenemy@gmail.com"}' \
-H 'Content-Type: application/json' \
-H 'Authorization: JWT {{token}}'
Response
{"success": 1}
Device driving statistics
GET /v1.1/devices/:dongle_id/stats
Returns aggregate driving statistics for a device
curl 'https://api.commadotai.com/v1.1/devices/02ec6bea180a4d36/stats' \
-H 'Authorization: JWT {{token}}'
Response
{
"all": {
"distance": 13026.936680094295,
"minutes": 23809,
"routes": 1349
},
"week": {
"distance": 105.20453522778553,
"minutes": 372,
"routes": 28
}
}
Response
JSON object with keys "all" and "week", each of which has this format:
Key | Type | Description |
---|---|---|
"distance" | (float) | Total miles driven in time period |
"minutes" | (integer) | Total minutes driven in time period |
"routes" | (integer) | Count of routes in time period |
Device users
GET /v1/devices/:dongle_id/users
List users with access to a device
curl 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/users' \
-H 'Authorization: JWT {{token}}'
Response
[
{
"email": "deviceowner@comma.ai",
"permission": "owner"
},
{
"email": "devicereader@comma.ai",
"permission": "read_access"
}
]
Response
JSON array of user objects.
Key | Type | Description |
---|---|---|
string | User email | |
permission | string | Device permission, one of ("owner", "read_access") |
Device boot logs
GET /v1/devices/:dongle_id/bootlogs
Returns most recent bootlogs uploaded from a device.
curl 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/bootlogs' \
-H 'Authorization: JWT {{token}}'
Response
[
"https://commadata2.blob.core.windows.net/commadata2/02ec6bea180a4d36/boot/2019-10-14--09-47-45.bz2?se=2019-10-16T17%3A52%3A03Z&sp=r&sv=2018-03-28&sr=b&rscd=attachment%3B%20filename%3D02ec6bea180a4d36_boot_2019-10-14--09-47-45.bz2&sig=sig/4%3D"
]
Response
JSON array of URLs of bootlog files. Files are available at each URL for one hour after time of API call.
Device crash logs
GET /v1/devices/:dongle_id/crashlogs
Returns most recent crashlogs uploaded from a device.
curl 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/crashlogs' \
-H 'Authorization: JWT {{token}}'
Response
[
"https://commadata2.blob.core.windows.net/commadata2/02ec6bea180a4d36/crash/2019-10-14--09-47-45.bz2?se=2019-10-16T17%3A52%3A03Z&sp=r&sv=2018-03-28&sr=b&rscd=attachment%3B%20filename%3D02ec6bea180a4d36_crash_2019-10-14--09-47-45.bz2&sig=sig/4%3D"
]
Response
JSON array of URLs of crashlog files. Files are available at each URL for one hour after time of API call.
Routes
Segments
GET /v1/devices/:dongle_id/segments
Returns time-sorted list of segments, each of which includes basic metadata derived from openpilot log.
curl 'https://api.commadotai.com/v1/devices/02ec6bea180a4d36/segments?from=1558508400000&to=1559718000000' \
-H 'Authorization: JWT {{token}}'
Parameters
from required
The lower bound on the start time of returned segments, in milliseconds since epoch.
to optional
The upper bound on end time of returned segments, in milliseconds since epoch. If omitted, defaults to now.
[
{
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--0",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"number": 0,
"git_remote": "git@github.com:commaai/openpilot.git",
"start_time_utc_millis": 1558505835614,
"proc_dcamera": -1,
"radar": false,
"create_time": 1558505900,
"hpgps": true,
"end_time_utc_millis": 1558505895587,
"end_lng": -117.0,
"start_lng": -117.0,
"passive": false,
"proc_log": 40,
"version": "0.5.12",
"git_branch": "master",
"end_lat": 32.0,
"proc_camera": 40,
"devicetype": 3,
"start_lat": 32.0,
"git_dirty": true,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/aaaaaaa_2019-05-21--23-17-14/0",
"length": 0.00179515,
"dongle_id": "0375fdf7b1ce594d",
"can": true,
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2"
}
]
Response
JSON array of segment objects. Each segment has the following keys:
Key | Type | Description |
---|---|---|
"git_remote" | string | Git remote from openpilot log InitData |
"start_time_utc_millis" | integer | Milliseconds since epoch of segment start time, from GPS |
"number" | integer | Segment number |
"proc_dcamera" | integer | Driver camera file status. See Segment File Status below |
"radar" | boolean | True if segment contains radar tracks in CAN |
"create_time" | integer | time of upload_url call for first file uploaded of segment |
"hpgps" | boolean | True if segment has ublox packets |
"end_time_utc_millis" | integer | Milliseconds since epoch of segment end time, from GPS |
"end_lng" | float | Last longitude recorded in segment, from GPS |
"start_lng" | float | First longitude recorded in segment, from GPS |
"passive" | boolean | True if openpilot was running in passive mode. From openpilot log InitData |
"canonical_name" | string | Segment name |
"proc_log" | Log file status. See Segment File Status below | |
"version" | string | Version string from openpilot log InitData |
"git_branch" | string | Git branch from openpilot log InitData |
"end_lat" | float | Last latitude recorded in segment from GPS |
"proc_camera" | Road camera file status. See Segment File Status below | |
"canonical_route_name" | string | Route name |
"devicetype" | integer | 3 is EON |
"start_lat" | float | First latitude recorded in segment from GPS |
"git_dirty" | boolean | Git dirty flag from openpilot log InitData |
"url" | string | Signed URL from which route.coords and jpegs can be downloaded (see Derived Data) |
"length" | float | Sum of distances between GPS points, miles |
"dongle_id" | string | Dongle ID |
"can" | boolean | True if log has at least 1 can message |
"git_commit" | string | Git commit from openpilot log InitData |
Segment File Status
status | code |
---|---|
upload_url_sent | 0 |
received | 10 |
enqueued | 20 |
processing | 30 |
processed | 40 |
Route Info
GET /v1/route/:route_name/
Returns information about the provided route. Authenticated user must have ownership of or read access to device from which route was uploaded.
curl https://api.commadotai.com/v1/route/99c94dc769b5d96e\|2019-05-17--17-31-58/ \
-H 'Authorization: JWT {{token}}'
Response
{
"git_remote": "git@github.com:commaai/openpilot.git",
"start_lat": 32.0,
"hpgps": true,
"create_time": 1558654768,
"maxdcamera": 2,
"user_id": null,
"end_lng": -117.0,
"start_lng": -117.0,
"passive": false,
"platform": "HONDA CIVIC 2016 TOURING",
"version": "0.5.12",
"end_lat": 32.0,
"git_branch": "devel",
"maxcamera": 2,
"proclog": 2,
"maxlog": 2,
"devicetype": 3,
"proccamera": 2,
"radar": true,
"git_dirty": true,
"init_logmonotime": 1932707747489,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/99c94dc769b5d96e/aaaaaaaaa_2019-05-17--17-31-58",
"length": 0,
"dongle_id": "99c94dc769b5d96e",
"can": true,
"git_commit": "39448abbb5bfc7ac1ae6424cd90b94a475ca12fa",
"fullname": "99c94dc769b5d96e|2019-05-17--17-31-58"
}
Response
Key | Type | Description |
---|---|---|
"git_remote" | string | Git remote from openpilot log InitData |
"radar" | boolean | True if any segment in route contains radar tracks in CAN |
"create_time" | integer | time of upload_url call for first file uploaded of route |
"hpgps" | boolean | True if any segment in route has ublox packets |
"end_lng" | float | Last longitude recorded in route, from GPS |
"start_lng" | float | First longitude recorded in route, from GPS |
"passive" | boolean | True if openpilot was running in passive mode. From openpilot log InitData |
"version" | string | Version string from openpilot log InitData |
"git_branch" | string | Git branch from openpilot log InitData |
"end_lat" | float | Last latitude recorded in route from GPS |
"fullname" | string | Route name |
"devicetype" | integer | 3 is EON |
"start_lat" | float | First latitude recorded in route from GPS |
"git_dirty" | boolean | Git dirty flag from openpilot log InitData |
"init_logmonotime" | integer | Minimum logMonoTime from openpilot log |
"url" | string | Signed URL from which route.coords and jpegs can be downloaded (see Derived Data) |
"length" | float | Sum of distances between GPS points, miles |
"dongle_id" | string | Dongle ID |
"can" | boolean | True if log has at least 1 can message |
"git_commit" | string | Git commit from openpilot log InitData |
"user_id" | string | User ID of device owner |
"maxlog" | integer | Maximum log segment number uploaded |
"proclog" | integer | Maximum log segment number processed |
"maxcamera" | integer | Maximum camera segment number uploaded |
"proccamera" | integer | Maximum camera segment number processed |
"maxdcamera" | integer | Maximum front camera segment number uploaded |
Route Segments
GET /v1/route/:route_name/segments
Returns list of segments comprising a route. Authenticated user must have ownership of or read access to device from which route was uploaded.
curl https://api.commadotai.com/v1/route/0375fdf7b1ce594d\|2019-05-21--23-17-14/segments \
-H 'Authorization: JWT {{token}}'
Response
[
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--5",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558506455,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7416,
"end_lng": -117.18,
"end_time_utc_millis": 1558506159491,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.0267973,
"number": 5,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7415,
"start_lng": -117.18,
"start_time_utc_millis": 1558506135585,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/5",
"version": "0.5.12"
},
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--4",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558506337,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7414,
"end_lng": -117.18,
"end_time_utc_millis": 1558506135580,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.895458,
"number": 4,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7309,
"start_lng": -117.171,
"start_time_utc_millis": 1558506075584,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/4",
"version": "0.5.12"
},
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--3",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558506214,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7304,
"end_lng": -117.17,
"end_time_utc_millis": 1558506075581,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.51377,
"number": 3,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7258,
"start_lng": -117.167,
"start_time_utc_millis": 1558506015585,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/3",
"version": "0.5.12"
},
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--2",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558506095,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7258,
"end_lng": -117.167,
"end_time_utc_millis": 1558506015584,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.275832,
"number": 2,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7218,
"start_lng": -117.166,
"start_time_utc_millis": 1558505955274,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/2",
"version": "0.5.12"
},
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--1",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558505980,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7217,
"end_lng": -117.166,
"end_time_utc_millis": 1558505955571,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.0933126,
"number": 1,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7202,
"start_lng": -117.167,
"start_time_utc_millis": 1558505895585,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/1",
"version": "0.5.12"
},
{
"can": true,
"canonical_name": "0375fdf7b1ce594d|2019-05-21--23-17-14--0",
"canonical_route_name": "0375fdf7b1ce594d|2019-05-21--23-17-14",
"create_time": 1558505900,
"devicetype": 3,
"dongle_id": "0375fdf7b1ce594d",
"end_lat": 32.7202,
"end_lng": -117.167,
"end_time_utc_millis": 1558505895587,
"git_branch": "master",
"git_commit": "8b7b90ce71eda504902f3a3c183ff5151bfac0d2",
"git_dirty": true,
"git_remote": "git@github.com:commaai/openpilot.git",
"hpgps": true,
"length": 0.00179515,
"number": 0,
"passive": false,
"proc_camera": 40,
"proc_dcamera": -1,
"proc_log": 40,
"proc_qlog": null,
"radar": false,
"start_lat": 32.7231,
"start_lng": -117.169,
"start_time_utc_millis": 1558505835614,
"url": "https://chffrprivate.blob.core.windows.net/chffrprivate3/v2/0375fdf7b1ce594d/39b636f2cde7d3e78e47d30c99fcdb62_2019-05-21--23-17-14/0",
"version": "0.5.12"
}
]
Response
Returns JSON array of segments. See Segments
Raw driving data
Files
GET /v1/route/:route_name/files
Retrieve uploaded files for a route. Calls to this API are rate limited to 5 per minute.
curl https://api.commadotai.com/v1/route/99c94dc769b5d96e\|2019-05-17--17-31-58/files \
-H 'Authorization: JWT {{token}}'
Response
{
"cameras": [
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/0/fcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--0--fcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=WHR7QdvxYs%2BhsM5b1inMCpgAErknsmPqW0G0KNk%2B8BQ%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/1/fcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--1--fcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=b/q0wRkyUfdkOnxhedZ3AfEVV6dNBIqWJmDKJ2iMYXw%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/2/fcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--2--fcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=3jTlj3zehVAkr4iPg7c9kzUhD6VTNioPws0tmNlvWmg%3D&se=2019-06-06T02%3A23%3A16Z"
],
"dcameras": [
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/0/dcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--0--dcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=L4Apvh4NZbzz8FEE2sHC0Y6ShUiKRR99jsmBUuGOC4c%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/1/dcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--1--dcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=03ayVwQ0VBIj9cfgOwj892GK2IZFq9U/HH%2BltEF9gB0%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/2/dcamera.hevc?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--2--dcamera.hevc&sr=b&sp=r&sv=2018-03-28&sig=r9Df0Yt72IFNNXU8FT85gkkXebw%2Bv2uOc0DXvyuu%2B%2B4%3D&se=2019-06-06T02%3A23%3A16Z"
],
"logs": [
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/0/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--0--rlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=Yxe2QiC88aoNRwxHQsVuunRWa6MaJDIZitktOY43PfA%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/1/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--1--rlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=xRGalraKsT9PWjtyL2SCr7IqnzvxVwm0ihgvha1iNLk%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/2/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--2--rlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=60%2BJSFBn8vveU0nc3Sld1iUIiAiJBRa6PBhFl4deWWg%3D&se=2019-06-06T02%3A23%3A16Z"
],
"qlogs": [
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/0/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--0--qlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=Yxe2QiC88aoNRwxHQsVuunRWa6MaJDIZitktOY43PfA%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/1/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--1--qlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=xRGalraKsT9PWjtyL2SCr7IqnzvxVwm0ihgvha1iNLk%3D&se=2019-06-06T02%3A23%3A16Z",
"https://commadata2.blob.core.windows.net/commadata2/99c94dc769b5d96e/2019-05-17--17-31-58/2/rlog.bz2?rscd=attachment%3B%20filename%3D99c94dc769b5d96e_2019-05-17--17-31-58--2--qlog.bz2&sr=b&sp=r&sv=2018-03-28&sig=60%2BJSFBn8vveU0nc3Sld1iUIiAiJBRa6PBhFl4deWWg%3D&se=2019-06-06T02%3A23%3A16Z"
],
"qcameras": []
}
Response
"cameras": Array of signed URLs to fcamera.hevc
"dcameras": Array of signed URLs to dcamera.hevc
"logs": Array of signed URLs to rlog.bz2
"qlogs": Array of signed URLs to qlog.bz2
"qcameras": Array of signed URLs to qcamera.ts
URLs are valid for 1 hour. All arrays are sorted by segment number ascending.
Video Stream
Base URL: https://video.comma.ai
Rear Camera Stream
GET /hls/:dongle_id/:route_signature/index.m3u8
Returns rear camera HLS stream index of MPEG-TS fragments
route_signature is the 3rd from last path component of a url
from the segments endpoint.
curl https://video.comma.ai/hls/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47/index.m3u8
Response
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:3.049958,
8_61.ts?v=2
#EXTINF:3.049955,
69_61.ts?v=2
#EXTINF:3.049955,
130_61.ts?v=2
#EXTINF:3.049958,
191_61.ts?v=2
#EXTINF:3.049970,
252_61.ts?v=2
#EXTINF:3.049955,
313_61.ts?v=2
#EXTINF:3.050007,
374_61.ts?v=2
#EXTINF:3.049913,
435_61.ts?v=2
#EXTINF:3.049942,
496_61.ts?v=2
#EXTINF:3.049964,
557_61.ts?v=2
#EXTINF:3.049955,
618_61.ts?v=2
Front Camera Stream
GET /hls/:dongle_id/:route_signature/dcamera/index.m3u8
Returns front camera HLS stream index of MPEG-TS fragments
route_signature is the 3rd from last path component of a url
from the segments endpoint.
curl https://video.comma.ai/hls/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47/dcamera/index.m3u8
Response
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:3.049958,
8_61.ts?v=2
#EXTINF:3.049955,
69_61.ts?v=2
#EXTINF:3.049955,
130_61.ts?v=2
#EXTINF:3.049958,
191_61.ts?v=2
#EXTINF:3.049970,
252_61.ts?v=2
#EXTINF:3.049955,
313_61.ts?v=2
#EXTINF:3.050007,
374_61.ts?v=2
#EXTINF:3.049913,
435_61.ts?v=2
#EXTINF:3.049942,
496_61.ts?v=2
#EXTINF:3.049964,
557_61.ts?v=2
#EXTINF:3.049955,
618_61.ts?v=2
Derived Data
GPS Path
After openpilot uploads a log, a JSON array of GPS coordinates interpolated at 1hz is exposed at a signed URL in the cloud. As segments are uploaded, route.coords
will be appended to atomically.
To access the GPS path, first obtain a segment url
key from the /v1/devices/:dongle_id/segments
response. Chop off the last path component, which represents the segment number. Append route.coords
. For example:
https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47/route.coords
Video Frames (every 5s)
JPEGs are extracted every 5s from road camera video and are exposed at a signed URL in the cloud.
To access the JPEGs, first obtain a segment url
key from the /v1/devices/:dongle_id/segments
response. Chop off the last path component, which represents the segment number. Append secN.jpg
where N is the 0-indexed number of seconds since start of the route. For example:
https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47/sec400.jpg
Events
Events are extracted from segments, first obtain a segment url
, append events.json
, for example:
https://chffrprivate.blob.core.windows.net/chffrprivate3-permanent/v2/cb38263377b873ee/78392b99580c5920227cc5b43dff8a70_2017-06-12--18-51-47/0/events.json
Response
[
{
"data": {
"pre_soft_disable": false,
"end_offset_nanos": 464369,
"alertSize": 2,
"end_time": 466342645882391,
"alertType": "startup",
"end_route_offset_millis": 15199,
"end_route_offset_nanos": 464369,
"should_take_control": false,
"end_offset_millis": 15199,
"alertText1": "Be ready to take over at any time",
"alertStatus": 0,
"alertText2": "Always keep hands on wheel and eyes on road",
},
"route_offset_nanos": 817760,
"offset_millis": 237,
"time": 466327684235782,
"type": "alert",
"offset_nanos": 817760,
"route_offset_millis": 237
}
]
Disengagement event
{
"data": {
"is_planned": false
},
"route_offset_nanos": 985946,
"offset_millis": 45087,
"time": "161093962680481",
"type": "disengage",
"offset_nanos": 942170,
"route_offset_millis": 525093
}
- Disengagements from controlsState (used for explorer timeline color)
Engagement event
{
"route_offset_nanos": 232202,
"offset_millis": 12963,
"time": "160941836926737",
"type": "engage",
"offset_nanos": 100204,
"route_offset_millis": 372968
}
- Engagements from controlsState (used for explorer timeline color)
Alert event
{
"data": {
"pre_soft_disable": false,
"end_offset_nanos": 824459,
"alertSize": 2,
"end_time": "156946181483417",
"alertType": "steerSaturated",
"end_route_offset_millis": 532376,
"end_route_offset_nanos": 180003,
"should_take_control": true,
"end_offset_millis": 52400,
"alertText1": "TAKE CONTROL",
"alertStatus": 1,
"alertText2": "Turn Exceeds Steering Limit"
},
"route_offset_nanos": 205578,
"offset_millis": 47070,
"time": "156940851508992",
"type": "alert",
"offset_nanos": 850034,
"route_offset_millis": 527046
}
- Alerts from alert packet (used for explorer timeline color)
Steer override event
{
"data": {
"is_planned": false,
"end_route_offset_millis": 877196,
"end_time": "161446064800451",
"end_offset_millis": 37255,
"end_offset_nanos": 521861,
"end_route_offset_nanos": 105916
},
"route_offset_nanos": 105243,
"offset_millis": 26305,
"time": "161435114799778",
"type": "disengage_steer",
"offset_nanos": 521188,
"route_offset_millis": 866246
}
- Steer override (not used by any client).
Note: The bits is_planned
and pre_soft_disable
are set in pipeline based on temporal correspondence with an alert for which we expect a disengagement.
openpilot
openpilot auth
POST https://api.commadotai.com/v2/pilotauth/
Query parameters
imei: Device IMEI
imei2: Device IMEI, second slot
serial: Device Serial
public_key: 2048-bit RSA Public Key
register_token: JWT token signed by your private key containing payload: {"register": True}
curl -X POST 'https://api.commadotai.com/v2/pilotauth/?imei=000000000000000&imei2=000000000000001&serial=aaaaaaaa&public_key=ssh-rsa%20AAAAB3NzaC1yc2EAAAADAQABAAABAQDeEAshPfzEDsSg8yZnidU8%2BGZSw%2BjS21vcoDlnrnI/3SQ8njvY0o6hHIt9Soxf%2BvnNF9amZ51tysblNIhkF9igwqXKNaEzIX2MKJSwp0rNdJSoLM8SSYBNlfyFUTsoakW2p6FQ9E01RgspFR8xBT91lrJ6eKKKmYP/P24mF6KfgdZ57%2BvTehmrj5MJi14lN18q8KM8nyppNvB5t0ijMeBq64x0TZig3o7rQxzzX0uMemNWZ3fXADL7lJUcyNO8Vv70%2BAddP9Ek8zgna7msUbzwbV1O1eUb9t3jlKHTN7zhfTXrxzwoNETHMn0569rZFmqfUf%2BHBEKLgUck1QMZIkRX%20root%40localhost®ister_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWdpc3RlciI6dHJ1ZSwiZXhwIjoxNTU5ODUzNTA3fQ.h5RMQ4ThPDy3Otadq0pcmnTROdXDklfxj6ItLqzxc8sNzioMa9qBeBRA22H75N11ucAOwxaF6ckO5AGDcDf5VwMwGbdibaVnTfUHP4mofz6usD-92lJbzQ1k0YwebPftBAoL4epRfS52Z1JVVLxNwCW9Mb9rexnc_tn2S7JQzHJUb1BLGSGengC1MtReXvIIjDK9FP-KAI9ZluvzIXnNtGvVfzJiVPwMQzmY4xRUewVXUJPPs6tv1oz26UW4Kd9aYhQo4KJAIUTAvY0gA_SYrcZIzC1pFcHY50Qot2HqW4HdJcoaXWqaWakbz4xUpswbiaQi1bdZoVa8b5Ht9r8p_g'
Response
{
"dongle_id": "02c45f73a2e5c6e9",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6ImZvbyIsImlhdCI6MTU2MDc1NDUzMywibmJmIjoxNTYwNzU0NTMzLCJleHAiOjE1OTIyOTA1MzN9.V34lp0Nq0EZMw7b5I8xnZaMvIbS2eisUsrFbXg4itaY"
}
Response
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | Dongle ID |
"access_token" | (string) | JWT token (see Authentication) |
Athena WebSocket
Listen for inbound JSON-RPC requests. This is used by openpilot's athenad.py
.
Base URL: wss://athena.comma.ai:8765
/:dongle_id
curl --include \
--no-buffer \
--header "Connection: Upgrade" \
--header "Upgrade: websocket" \
--header "Host: athena.comma.ai:8765" \
--header "Origin: https://athena.comma.ai:8765" \
--cookie "jwt={{device_token}}" \
https://athena.comma.ai:8765/02c45f73a2e5c6e9
Upload URL
Request a URL to which an openpilot file can be uploaded via PUT request. This endpoint only accepts tokens signed with a device private key (openpilot 0.6.3 and newer.)
V 1.4
GET /v1.4/:dongle_id/upload_url/
Parameters
Key | Description |
---|---|
path | segment directory and name of file to upload from openpilot data directory. for example, 2019-06-06--11-30-31--9/fcamera.hevc |
expiry_days | number of days the url should be valid. Valid values beteen 1 and 30. Optional, default is 1 day. |
curl https://api.commadotai.com/v1.4/ccfab3437bea5257/upload_url/?path=2019-06-06--11-30-31--9/fcamera.hevc&expiry_days=1 \
-H 'Authorization: JWT jwt_signed_with_device_private_key'
Response
{
"url": "https://commaincoming.blob.core.windows.net/commaincoming/239e82a1d3c855f2/2019-06-06--11-30-31/9/fcamera.hevc?sr=b&sp=c&sig=cMCrZt5fje7SDXlKcOIjHgA0wEVAol71FL6ac08Q2Iw%3D&sv=2018-03-28&se=2019-06-13T18%3A43%3A01Z"
}
Response
Key | Type | Description |
---|---|---|
"url" | (string) | URL to which a PUT request can be sent with file contents |
Batch upload urls
POST /v1/:dongle_id/upload_urls/
Request body
JSON object with keys:
Key | Type | Description |
---|---|---|
paths | (list) | list of files to upload from openpilot data directory. for example, ["2019-06-06--11-30-31--9/fcamera.hevc", "2019-06-06--11-30-31--9/ecamera.hevc"] |
expiry_days | (integer) | number of days the url should be valid. Valid values beteen 1 and 30. Optional, default is 1 day. |
curl https://api.commadotai.com/v/ccfab3437bea5257/upload_urls/ \
-d '{"paths":["2019-06-06--11-30-31--9/fcamera.hevc", "2019-06-06--11-30-31--9/ecamera.hevc"]}' \
-H 'Authorization: JWT jwt_signed_with_device_private_key'
Response
[
{
"url": "https://commaincoming.blob.core.windows.net/commaincoming/239e82a1d3c855f2/2019-06-06--11-30-31/9/fcamera.hevc?sr=b&sp=c&sig=cMCrZt5fje7SDXlKcOIjHgA0wEVAol71FL6ac08Q2Iw%3D&sv=2018-03-28&se=2019-06-13T18%3A43%3A01Z"
},
{
"url": "https://commaincoming.blob.core.windows.net/commaincoming/239e82a1d3c855f2/2019-06-06--11-30-31/9/ecamera.hevc?sr=b&sp=c&sig=cMCrZt5fje7SDXlKcOIjHgA0wEVAol71FL6ac08Q2Iw%3D&sv=2018-03-28&se=2019-06-13T18%3A43%3A01Z"
}
]
Response
JSON list with objects containing:
Key | Type | Description |
---|---|---|
"url" | (string) | URL to which a PUT request can be sent with file contents |
Athena
Athena HTTP
Send JSON-RPC requests to the active websocket client for a given device identified by Dongle ID.
Some methods types support offline queueing of messages until the device comes online, see expiry
.
Response will indicate if the message has been put in the offline queue.
Base URL: https://athena.comma.ai
POST /:dongle_id
Request body
{
"method": "getMessage",
"params": {"service": "deviceState", "timeout": 5000},
"jsonrpc": "2.0",
"id": 0
}
JSON-RPC payload with keys:
Key | Type | Description |
---|---|---|
"method" | (string) | json-rpc method - see openpilot athenad.py for supported methods |
"params" | (object) | method-specific params. For getMessage: |
"params.service" | (string) | service name (see openpilot service_list.yaml ) |
"params.timeout" | (integer) | milliseconds client should wait for message from service |
"jsonrpc" | (string) | constant, "2.0" |
"id" | (integer) | constant, 0 |
"expiry" | (integer) (optional) | UTC unix timestamp in seconds at which this message will no longer be retried when device comes online, only works for some specific methods. |
curl https://athena.comma.ai/02c45f73a2e5c6e9 \
-d '{"method":"getMessage","params":{"service":"deviceState","timeout":5000},"jsonrpc":"2.0","id":0}' \
-H 'Authorization: JWT {{token}}'
Response
{
"jsonrpc": "2.0",
"result": {
"deviceState": {
"batteryStatus": "Discharging",
"freeSpace": 0.9546145796775818,
"bat": 28700,
"usbOnline": false,
"batteryCurrent": 330808,
"startedTs": 0,
"mem": 333,
"chargingError": false,
"cpu2": 333,
"cpu3": 333,
"cpu0": 343,
"cpu1": 323,
"fanSpeed": 0,
"batteryVoltage": 4200414,
"chargingDisabled": false,
"started": false,
"batteryPercent": 93,
"gpu": 309,
"thermalStatus": "green"
},
"valid": true,
"logMonoTime": 107226885676532
},
"id": "ba0daa7a-a208-410f-8f11-1e1e6f29edeb"
}
Response
JSON-RPC response object with keys:
Key | Type | Description |
---|---|---|
"jsonrpc" | string | "2.0", constant |
"result" | (method-specific) | method-specific result. For getMessage , it's a zmq message encoded as dictionary. see openpilot log.capnp . For messages put in offline queue, result is string containing Device offline, message queued . |
"id" | string | request ID |
offline queue
Fetch messages stored for delivery once device comes online.
GET /v1/devices/:dongle_id/athena_offline_queue
curl https://api.comma.ai/v1/devices/02c45f73a2e5c6e9/athena_offline_queue \
-H 'Authorization: JWT {{token}}'
Response
[{
"method": "uploadFilesToUrls",
"jsonrpc": "2.0",
"params": {
"files_data": [
["2022-01-05--11-35-48--9/fcamera.hevc", "https://commaincoming.blob.core.windows.net/commaincoming/02c45f73a2e5c6e9/2022-01-05--11-35-48/9/fcamera.hevc?sr=b&sp=cw&sig=cMCrZt5fje7SDXlKcOIjHgA0wEVAol71FL6ac08Q2Iw%3D&sv=2018-03-28&se=2019-06-13T18%3A43%3A01Z", {"x-ms-blob-type": "BlockBlob"}],
["2022-01-05--11-35-48--9/ecamera.hevc", "https://commaincoming.blob.core.windows.net/commaincoming/02c45f73a2e5c6e9/2022-01-05--11-35-48/9/ecamera.hevc?sr=b&sp=cw&sig=cMCrZt5fje7SDXlKcOIjHgA0wEVAol71FL6ac08Q2Iw%3D&sv=2018-03-28&se=2019-06-13T18%3A43%3A01Z", {"x-ms-blob-type": "BlockBlob"}]
]
},
"expiry": 1642423439
}]
Response
List of athena payloads, including expiry. See Athena HTTP request body.
Billing
Subscription Status
GET /v1/prime/subscription
Retrieve subscription status for a device
curl https://billing.comma.ai/v1/prime/subscription?dongle_id=b0c9d2329ad1606b \
-H 'Authorization: JWT {{token}}'
Query Parameters
dongle_id required
The dongle ID of the device
Response
{
"amount": 2400,
"is_prime_sim": true,
"next_charge_at": 1595720380,
"sim_id": "0000000000000000000",
"subscribed_at": 1587944381,
"trial_claim_end": null,
"trial_claimable": false,
"trial_end": 1595720380,
"user_id": "google_104654435692089730759"
}
Response
JSON object with keys:
Key | Type | Description |
---|---|---|
"amount" | (integer) | Monthly subscription cost, in USD cents |
"is_prime_sim" | (bool) | True if subscription includes data plan |
"next_charge_at" | (integer) | Unix timestamp of next scheduled subscription charge |
"sim_id" | (string, nullable) | 19-digit SIM ID, non-null if subscription includes data plan |
"subscribed_at" | (integer) | Unix timestamp of subscription start time |
"trial_claim_end" | (integer, nullable) | Unix timestamp of deadline to claim trial, if eligible |
"trial_claimable" | (bool) | True if eligible for trial and before |
"trial_end" | (integer) | Unix timestamp of trial end |
"user_id" | (string) | OAuth user ID of subscription customer |
Activate Subscription
POST /v1/prime/pay
Activate subscription for a device, optionally with a compatible SIM card.
curl https://billing.comma.ai/v1/prime/pay \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"dongle_id": "b0c9d2329ad1606b", "sim_id": "0000000000000000000", "stripe_token": "stripe_token"}'
Request Body
JSON object with keys:
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | Device dongle ID |
"sim_id" | (string, nullable) | 19-digit SIM ID to be associated with subscription data plan. Null if subscription does not include data plan. |
"stripe_token" | (string) | Card token from Stripe client API (https://stripe.com/docs/api/tokens) |
Responses
{"success": 1}
{"error": "Subscription already active"}
Response
JSON object with keys:
Key | Type | Description |
---|---|---|
"success" | integer | 1 if subscription activated |
"error" | string (optional) | Error description |
Get Payment Source
GET /v1/prime/payment_source
Get current payment source
curl https://billing.comma.ai/v1/prime/payment_source \
-H 'Authorization: JWT {{token}}'
{
"brand": "Visa",
"country": "US",
"exp_month": 12,
"exp_year": 2026,
"last4": "4242",
"tokenization_method": "apple_pay"
}
Response
JSON object with keys:
Key | Type | Description |
---|---|---|
"brand" | (string) | Card brand |
"country" | (string) | Card country |
"exp_month" | (integer) | Card expiration month |
"exp_year" | (integer) | Card expiration year |
"last4" | (string) | Last four digits of card number |
"tokenization_method" | (string, nullable) | One of ("apple_pay", "android_pay", null) |
Set Payment Source
POST /v1/prime/payment_source
Update payment source associated with an account. Stripe securely stores all card information.
curl https://billing.comma.ai/v1/prime/payment_source \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"stripe_token": "some_stripe_token"}'
Request Body
JSON object with keys:
Key | Type | Description |
---|---|---|
"stripe_token" | (string) | Card token from Stripe client API (https://stripe.com/docs/api/tokens) |
Response
{
"brand": "Visa",
"country": "US",
"exp_month": 12,
"exp_year": 2026,
"last4": "4243",
"tokenization_method": null
}
Response
JSON object with keys:
Key | Type | Description |
---|---|---|
"brand" | (string) | Card brand |
"country" | (string) | Card country |
"exp_month" | (integer) | Card expiration month |
"exp_year" | (integer) | Card expiration year |
"last4" | (string) | Last four digits of card number |
"tokenization_method" | (string, nullable) | Non-null if payment source is tokenized using a mobile payment provider ("apple_pay", "android_pay"). Otherwise, null if card is used directly. |
Cancel Subscription
POST /v1/prime/cancel
Cancel subscription for device
curl https://billing.comma.ai/v1/prime/cancel \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"dongle_id": "b0c9d2329ad1606b"}'
Request Body
JSON object with keys:
Key | Type | Description |
---|---|---|
"dongle_id" | (string) | Device dongle ID associated with subscription to be cancelled |
{"success": 1}
Navigation
Set destination
POST /v1/navigation/:dongle_id/set_destination
Set navigation destination on device. If device is offline, the destination will be saved in the database to be retrieved when the device boots. Also updates navigation recents list.
curl -X POST https://api.commadotai.com/v1/navigation/0375fdf7b1ce594d/set_destination \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"place_name": "San Diego Airport", "place_details": "3225 N Harbor Dr, San Diego, CA 92101, United States", "latitude": 32.7304, "longitude": -117.195}'
Request body
JSON object
Key | Type | Description |
---|---|---|
"place_name" | (string) | Short name of destination |
"place_details" | (string) | Address details of destination, should not include short name |
"latitude" | (float) | Latitude, degrees |
"longitude" | (float) | Longitude, degrees |
Response
JSON object with keys:
Key | Type | Description |
---|---|---|
"success" | (bool) | Whether the destination is successfully set |
"saved_next" | (bool) | True if device was offline and destination is set to be retrieved on device startup |
"error" | (string, optional) | Error description |
Retrieve next destination
GET /v1/navigation/:dongle_id/next
Retrieve next location from database, this was set on Set destination if the device was offline. Next location is removed from database after this call and when a new destination is set.
curl https://api.commadotai.com/v1/navigation/0375fdf7b1ce594d/next \
-H 'Authorization: JWT {{token}}'
Query parameters
None
Response
null
if no destination is set, or JSON object:
Key | Type | Description |
---|---|---|
"place_name" | (string) | Short name of destination |
"place_details" | (string) | Address details of destination, should not include short name |
"latitude" | (float) | Latitude, degrees |
"longitude" | (float) | Longitude, degrees |
Retrieve saved locations
GET /v1/navigation/:dongle_id/locations
Retrieve saved locations from database.
curl https://api.commadotai.com/v1/navigation/0375fdf7b1ce594d/locations \
-H 'Authorization: JWT {{token}}'
Query parameters
None
Response
JSON array filled with objects (ordered by modfied
):
Key | Type | Description |
---|---|---|
"id" | (int) | identifier of this saved location |
"dongle_id" | (string) | dongle_id of device |
"place_name" | (string) | Short name of destination |
"place_details" | (string) | Address details of destination, should not include short name |
"latitude" | (float) | Latitude, degrees |
"longitude" | (float) | Longitude, degrees |
"save_type" | (string) | enum of favorite , recent |
"label" | (string, optional) | optional label for locations with save_type : favorite |
"modified" | (string) | when this saved location was last modified, useful for when save_type : recent |
Set saved locations
PUT /v1/navigation/:dongle_id/locations
Save new location in database.
curl -X PUT https://api.commadotai.com/v1/navigation/0375fdf7b1ce594d/locations \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"place_name": "San Diego Airport", "place_details": "3225 N Harbor Dr, San Diego, CA 92101, United States", "latitude": 32.7304, "longitude": -117.195, "save_type": "favorite", "label": "work"}'
Request body
JSON object:
Key | Type | Description |
---|---|---|
"place_name" | (string) | Short name of destination |
"place_details" | (string) | Address details of destination, should not include short name |
"latitude" | (float) | Latitude, degrees |
"longitude" | (float) | Longitude, degrees |
"save_type" | (string) | enum of favorite , recent , next |
"label" | (string, optional) | optional label for locations with save_type : favorite |
Response
{"success": true}
Update saved locations
PATCH /v1/navigation/:dongle_id/locations
DELETE /v1/navigation/:dongle_id/locations
Update or delete existing saved location in database.
curl -X PATCH https://api.commadotai.com/v1/navigation/0375fdf7b1ce594d/locations \
-H 'Authorization: JWT {{token}}' \
-H 'Content-Type: application/json' \
-d '{"id": 42, "save_type": "favorite", "label": "work"}'
Request body
JSON object:
Key | Type | Description |
---|---|---|
"id" | (int) | identifier of saved location |
"save_type" | (string, optional) | enum of favorite , recent , next |
"label" | (string, optional) | optional label for locations with save_type : favorite |
Response
{"success": true}