Rivnly API Reference
Base URL: https://app.rivnly.com
Authentication
All API endpoints require authentication via an API key passed in the Authorization header:
Authorization: Bearer rnly_your_api_key_here
API keys are created from the Rivnly settings page. Each key is scoped to the user who created it and can only access that user's vehicle data.
Scopes
| Scope | Access |
|---|---|
read |
Vehicle state, drives, charging history, snapshots, maintenance |
commands |
Send vehicle commands (wake, lock, frunk, etc.) |
Rate Limiting
Each API key has a configurable rate limit (default: 60 requests per minute). When exceeded, the API returns 429 Too Many Requests.
Errors
All errors return JSON with an error field:
{ "error": "Not authenticated" }
| Status | Meaning |
|---|---|
401 |
Missing or invalid API key |
403 |
API key missing required scope |
404 |
Resource not found |
429 |
Rate limit exceeded |
Vehicles
GET /api/vehicles
List all vehicles associated with your account.
Scope: read
Response:
[
{
"id": 1,
"rivian_vehicle_id": "01-248753095",
"vin": "7PDSGBBP5TN088960",
"model": "R1S",
"model_year": 2026,
"trim_option": "R1S Tri",
"exterior_color": "El Cap Granite paint",
"interior_color": "Black Mountain + Brown Ash Wood",
"wheel_option": "22\" Sport Dark",
"drive_system": "Tri-motor AWD",
"tonneau_option": null,
"charge_port": "NACS",
"max_vehicle_power": 215,
"drive_modes": ["everyday", "sport", "distance", "winter", "off_road_auto"],
"towing_drive_modes": ["everyday", "off_road_auto", "winter"],
"ccc_capable": true,
"ccc_ready": true,
"ccc_enabled": true
}
]
Note: Use the
rivian_vehicle_idvalue as the:vehicle_idpath parameter for all other endpoints.
Vehicle State
GET /api/vehicle/:vehicle_id/state
Fetch the current vehicle state from the Rivian API. Returns real-time data including battery, location, climate, doors/locks, and more.
Scope: read
Response:
{
"data": {
"vehicleState": {
"batteryLevel": { "timeStamp": "...", "value": 72.5 },
"batteryCapacity": { "value": 142.05 },
"distanceToEmpty": { "timeStamp": "...", "value": 401 },
"vehicleMileage": { "timeStamp": "...", "value": 735336 },
"gnssLocation": { "latitude": 38.544, "longitude": -121.269, "timeStamp": "..." },
"gnssSpeed": { "timeStamp": "...", "value": 0.0 },
"powerState": { "timeStamp": "...", "value": "ready" },
"gearStatus": { "timeStamp": "...", "value": "park" },
"driveMode": { "timeStamp": "...", "value": "everyday" },
"chargerState": { "timeStamp": "...", "value": "chrgr_sts_not_connected" },
"cabinClimateInteriorTemperature": { "timeStamp": "...", "value": 22.5 },
"doorFrontLeftLocked": { "timeStamp": "...", "value": "locked" },
"...": "..."
}
},
"_ws": {
"cloud_is_online": false,
"cloud_last_sync": "2026-04-14T14:59:34.512Z",
"tire_pressure_psi": { "frontLeft": 47.9, "frontRight": 48.1, "rearLeft": 47.5, "rearRight": 47.8 },
"ws_connected": true
}
}
Data units (raw from Rivian API):
| Field | Unit | Conversion |
|---|---|---|
vehicleMileage |
meters | / 1609.344 = miles |
distanceToEmpty |
km | * 0.621371 = miles |
gnssSpeed |
m/s | * 2.237 = mph, * 3.6 = km/h |
gnssAltitude |
meters (MSL) | * 3.28084 = feet |
cabinClimate*Temperature |
Celsius | * 9/5 + 32 = Fahrenheit |
batteryLevel |
percentage | 0-100 |
batteryCapacity |
kWh |
GET /api/vehicle/:vehicle_id/state/history
Historical vehicle state snapshots from the database.
Scope: read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
hours |
integer | 24 | Number of hours of history to return |
Response:
{
"snapshots": [
{
"id": 12345,
"captured_at": "2026-04-14T01:00:00+00:00",
"battery_level": 54.3,
"battery_capacity": 142.7,
"distance_to_empty": 301,
"vehicle_mileage": 735336,
"latitude": 38.544,
"longitude": -121.269,
"altitude": 35.2,
"speed": 0.0,
"charger_state": "chrgr_sts_not_connected",
"power_state": "ready",
"drive_mode": "everyday",
"gear_status": "park",
"cabin_temp_interior": 22.5,
"ota_current_version": "2026.03.0"
}
]
}
Note: Snapshot data has already been converted:
speedis in km/h,altitudeis meters above sea level (MSL, geoid-corrected).
GET /api/vehicle/:vehicle_id/last-connection
Last cloud connection sync timestamp.
Scope: read
GET /api/vehicle/:vehicle_id/ota
OTA update details (current and available versions).
Scope: read
GET /api/vehicle/:vehicle_id/range
Estimated range at a given state of charge.
Scope: read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
soc |
float | 80 | State of charge percentage (0-100) |
GET /api/vehicle/:vehicle_id/maintenance
Vehicle maintenance schedule and current mileage.
Scope: read
Response:
{
"maintenance": { "...": "Rivian maintenance schedule JSON" },
"model_year": 2026,
"vehicle_name": "R1S",
"trim": "R1S Tri",
"vin": "7PDSGBBP5TN088960",
"current_mileage_meters": 735336
}
GET /api/vehicle/:vehicle_id/enrollment-status
Check if a phone key is enrolled for vehicle commands.
Scope: read
Response:
{ "enrolled": true }
Drive Sessions
GET /api/vehicle/:vehicle_id/drives
List drive sessions, newest first (limit 50).
Scope: read
Response:
{
"drives": [
{
"id": 42,
"start_time": "2026-04-13T16:02:09+00:00",
"end_time": "2026-04-13T16:19:13+00:00",
"duration_seconds": 1024,
"distance_meters": 19288,
"distance_miles": 12.0,
"start_battery": 47.6,
"end_battery": 42.6,
"energy_used_kwh": 7.1,
"drive_mode": "everyday",
"start_latitude": 38.544,
"start_longitude": -121.269,
"end_latitude": 38.574,
"end_longitude": -121.408
}
]
}
GET /api/vehicle/:vehicle_id/drives/:drive_id
Single drive with GPS route, speed/elevation data, and computed stats.
Scope: read
Response:
{
"drive": { "...": "same fields as list above" },
"stats": {
"avg_speed_kmh": 62.4,
"max_speed_kmh": 118.1,
"avg_cabin_temp_c": 22.5,
"min_elevation_m": 6.2,
"max_elevation_m": 35.1,
"snapshot_count": 65
},
"snapshots": [
{
"captured_at": "2026-04-13T16:02:09+00:00",
"latitude": 38.544,
"longitude": -121.269,
"speed": 0.0,
"altitude": 35.2,
"battery_level": 47.6,
"gear_status": "park",
"...": "..."
}
]
}
Charging Sessions
GET /api/vehicle/:vehicle_id/charging/history
All completed charging sessions with aggregate totals.
Scope: read
Response:
{
"sessions": [
{
"id": 2006,
"start_time": "2026-04-13T20:10:16+00:00",
"end_time": "2026-04-13T20:27:45+00:00",
"duration_seconds": 1049,
"total_energy_kwh": 8.715,
"range_added_km": 37.0,
"start_battery": 38.3,
"end_battery": 44.6,
"cost_total": 6.27,
"cost_currency": "USD",
"vendor": "Tesla",
"city": "Folsom",
"is_home_charger": false,
"is_public": true,
"source": "rivian_api"
}
],
"totals": {
"session_count": 25,
"total_energy_kwh": 842.5,
"total_cost": 127.33,
"total_range_added_miles": 2104.7
}
}
GET /api/vehicle/:vehicle_id/charging/session/:session_id
Single charging session detail with battery snapshots captured during the charge window.
Scope: read
Response:
{
"session": { "...": "same fields as list above" },
"snapshots": [
{
"captured_at": "2026-04-13T20:10:32+00:00",
"battery_level": 38.3,
"charger_state": "charging_active",
"...": "..."
}
]
}
GET /api/vehicle/:vehicle_id/charging/live
Live charging data (when actively charging) and last completed session summary.
Scope: read
Response:
{
"data": {
"liveSession": null,
"chartData": null,
"lastSession": {
"id": 2006,
"total_energy_kwh": 8.715,
"range_added_km": 37.0,
"...": "..."
}
}
}
GET /api/vehicle/:vehicle_id/charging/schedule
Vehicle charging schedule configuration.
Scope: read
Vehicle Commands
Important: Most commands require BLE proximity to the vehicle. The API will accept the command, but execution requires a Bluetooth connection.
WAKE_VEHICLEmay work remotely.
POST /api/vehicle/:vehicle_id/command
Send a signed vehicle command.
Scope: commands
Request Body:
{ "command": "WAKE_VEHICLE" }
Valid Commands:
| Command | Description |
|---|---|
WAKE_VEHICLE |
Wake the vehicle (may work remotely) |
OPEN_FRUNK |
Open the front trunk |
CLOSE_FRUNK |
Close the front trunk |
OPEN_ALL_WINDOWS |
Open all windows |
CLOSE_ALL_WINDOWS |
Close all windows |
UNLOCK_ALL_CLOSURES |
Unlock all doors |
LOCK_ALL_CLOSURES |
Lock all doors |
ENABLE_GEAR_GUARD_VIDEO |
Enable Gear Guard video recording |
DISABLE_GEAR_GUARD_VIDEO |
Disable Gear Guard video recording |
HONK_AND_FLASH_LIGHTS |
Honk horn and flash lights |
OPEN_TONNEAU_COVER |
Open tonneau cover (R1T only) |
CLOSE_TONNEAU_COVER |
Close tonneau cover (R1T only) |
Response:
{
"data": {
"sendVehicleCommand": {
"id": "cmd-abc123",
"command": "WAKE_VEHICLE",
"state": 0
}
}
}
GET /api/vehicle/:vehicle_id/command/:command_id/status
Check the execution status of a previously sent command.
Scope: commands
Response:
{
"data": {
"getVehicleCommand": {
"id": "cmd-abc123",
"command": "WAKE_VEHICLE",
"state": 0
}
}
}
state: 0 indicates the command completed successfully.
POST /api/vehicle/:vehicle_id/enroll-phone
Enroll a virtual phone key for HMAC command signing. Required once before sending commands.
Scope: commands
Examples
cURL: Get vehicle list
curl -H "Authorization: Bearer rnly_your_key_here" \
https://app.rivnly.com/api/vehicles
cURL: Get drive history
curl -H "Authorization: Bearer rnly_your_key_here" \
https://app.rivnly.com/api/vehicle/01-248753095/drives
cURL: Get current vehicle state
curl -H "Authorization: Bearer rnly_your_key_here" \
https://app.rivnly.com/api/vehicle/01-248753095/state
Python
import requests
API_KEY = "rnly_your_key_here"
BASE_URL = "https://app.rivnly.com"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# List vehicles
vehicles = requests.get(f"{BASE_URL}/api/vehicles", headers=HEADERS).json()
vehicle_id = vehicles[0]["rivian_vehicle_id"]
# Get current state
state = requests.get(f"{BASE_URL}/api/vehicle/{vehicle_id}/state", headers=HEADERS).json()
battery = state["data"]["vehicleState"]["batteryLevel"]["value"]
print(f"Battery: {battery}%")
# Get drive history
drives = requests.get(f"{BASE_URL}/api/vehicle/{vehicle_id}/drives", headers=HEADERS).json()
for drive in drives["drives"][:5]:
miles = drive.get("distance_miles", 0)
kwh = drive.get("energy_used_kwh", 0)
print(f"Drive {drive['id']}: {miles} mi, {kwh} kWh")
JavaScript
const API_KEY = 'rnly_your_key_here';
const BASE = 'https://app.rivnly.com';
const headers = { Authorization: `Bearer ${API_KEY}` };
const vehicles = await fetch(`${BASE}/api/vehicles`, { headers }).then(r => r.json());
const vehicleId = vehicles[0].rivian_vehicle_id;
const state = await fetch(`${BASE}/api/vehicle/${vehicleId}/state`, { headers }).then(r => r.json());
console.log('Battery:', state.data.vehicleState.batteryLevel.value + '%');