Health check #
Liveness probe for uptime monitoring. Returns quickly, does not
require authentication, and does not hit the database. The
response shape is stable — monitoring tools can key on
status === "ok".
The Teslita API gives third-party applications read access to a Teslita user's vehicle, trip, charging, and pack-health data, plus a narrow set of write endpoints for triggering server-side work like a supercharger history sync.
The API is organised around REST, uses predictable resource-oriented URLs, accepts and returns JSON, and authenticates requests with bearer tokens. All requests run over TLS — plain HTTP is rejected.
https://api.teslita.com
Every API key belongs to a single Teslita user, and every request it authenticates resolves to that user's data. There is no multi-tenant key: a partner that needs access to more than one Teslita account needs one key per account. Keys are minted by the account owner and shown once at creation time — only a SHA-256 hash is stored server-side, so a lost key cannot be recovered and must be replaced.
Authenticate requests by sending your key in the
Authorization header as a bearer token. Keys look
like tsk_ followed by 40 URL-safe characters (~230
bits of entropy). Never commit them to source control, log them,
or send them to the browser — treat them the way you'd treat a
database password.
Three scopes are defined. A key may carry any combination.
read |
All GET endpoints: vehicles, trips, charging, pack health, settings. |
write |
Server-side data operations — for example, triggering a supercharger history sync. Does not include physical vehicle commands. |
control |
Physical commands sent to the vehicle: start / stop charging today, more to come. Separate from write so operators can grant data sync without granting car control. |
Calling an endpoint with a key that lacks the required scope
returns 403 forbidden.
A missing, malformed, or revoked key returns 401.
We do not distinguish between "not sent" and "sent but invalid"
in the error message to avoid helping credential stuffing.
Every timestamp is ISO-8601, always UTC, always suffixed Z.
Example: 2026-04-24T17:30:16Z.
Integer database IDs are serialised as strings in JSON to sidestep the 53-bit integer limit in JavaScript. Treat them as opaque — don't do arithmetic with them. VINs (17 uppercase characters) are the business key for vehicles throughout the API.
Distance in kilometres, energy in kWh, power in kW, voltage in V,
tyre pressure in bar, temperatures in °C. Costs are returned in
the session's native currency; partners are expected to convert
themselves if needed. Units are baked into field names where it
could be ambiguous (_kwh, _kmh,
_bar, _c).
List endpoints paginate cursor-style. Pass
?limit= (default 50, max 200) and
?cursor=. The response carries next_cursor
— pass it back as cursor to fetch the next page.
When next_cursor is null, you've reached
the end. Cursors are opaque; do not parse them.
?from= and ?to= accept either
ISO-8601 (2026-04-24T00:00:00Z) or the shorter
YYYY-MM-DD. Both bounds are inclusive and
interpreted as UTC.
Errors are returned as JSON with a stable shape so you can parse
them without switching on HTTP status alone. The code
is machine-readable and stable; the message is
human-readable and may change.
missing_auth401 Unauthorized |
No Authorization header was sent. |
invalid_auth401 Unauthorized |
Key is unknown, malformed, or revoked. |
forbidden403 Forbidden |
Key lacks a required scope (e.g. write). |
not_found404 Not Found |
Route doesn't exist, or resource isn't owned by this user. |
bad_request400 Bad Request |
A parameter is missing, malformed, or out of range. |
rate_limited429 Too Many Requests |
Per-key cap exceeded. Back off and retry after 60 seconds. |
tesla_not_connected409 Conflict |
User has no linked Tesla account — required for writes that proxy Tesla. |
upstream_error502 Bad Gateway |
A required upstream service (typically Tesla) failed. |
internal_error500 Internal Error |
Unexpected server-side failure. Retrying may help; if it persists, contact support. |
Every key has a fixed-window rate limit, measured per 60-second window. The default is 120 requests per minute. Operators can set a per-key override at mint time if a partner has a legitimate need for a higher ceiling.
Exceeding the limit returns 429 rate_limited. The
cap resets at the start of the next window. We recommend
exponential backoff with jitter for retries; a tight retry loop
will simply bounce off the same limit.
Rate limit counters are shared per-key, not per-IP. If you distribute calls across multiple servers using the same key, they all count toward the same bucket.
Every route carries the API version in the URL
(/v1/…). Within a version, we only make
additive changes: we may add new fields, new
endpoints, or new optional parameters, but we will not remove
existing fields, rename them, or change their types.
Breaking changes ship as a new version prefix
(/v2/…). Older versions are supported in parallel
for a documented deprecation window before retirement.
Treat unknown fields as optional — if you see a field you haven't seen before in a response, you can safely ignore it without breaking.
Liveness probe for uptime monitoring. Returns quickly, does not
require authentication, and does not hit the database. The
response shape is stable — monitoring tools can key on
status === "ok".
Returns the Teslita user your key belongs to, plus metadata about the key itself. Useful for the very first request — it confirms the key is valid, shows which account and scopes it carries, and lets you detect a stale or swapped-out key.
user.idstring |
The Teslita user's ID. Opaque — use for equality checks only. |
user.emailstring |
Account email. |
user.display_namestring | null |
Name the user set, if any. |
user.languagestring | null |
Two-letter language code (en, de, …). |
key.scopesarray<string> |
Scopes carried by this key. One or both of read, write. |
The user's display preferences, home location, and locale configuration. This is what drives how the Teslita UI itself renders numbers and dates — mirroring it in a partner app keeps experiences consistent.
languagestring | null | Two-letter code. |
pressure_unitstring | null | bar or psi. |
temperature_unitstring | null | celsius or fahrenheit. |
countrystring | null | ISO 3166-1 alpha-2 code. |
currencystring | null | ISO 4217 code (EUR, USD, …). |
timezonestring | null | IANA zone name. |
home.latitudenumber | null | Signed decimal degrees. |
home.longitudenumber | null | Signed decimal degrees. |
home_kwh_pricenumber | null | Unit price used to estimate cost of home-charging sessions. |
Every vehicle linked to the user's Tesla account. Includes
archived vehicles the user no longer owns — these have
disconnected_at set. Their historical trip and
charging data is preserved and still queryable.
data[].vinstring | 17-character Tesla VIN. Use as the path parameter on vehicle-scoped endpoints. |
data[].display_namestring | null | Name set in the Tesla app. |
data[].custom_namestring | null | Nickname set inside Teslita (overrides display_name in UIs). |
data[].modelstring | null | Model S, Model 3, Model X, Model Y, Cybertruck, Roadster, Semi. |
data[].telemetry_enabledboolean | Whether Fleet Telemetry is provisioned on the vehicle. |
data[].disconnected_attimestamp | null | Non-null if Tesla no longer returns this VIN on the user's fleet. |
Same shape as a single entry in list
vehicles, wrapped in a data envelope. Returns
404 not_found if the VIN is not owned by this user.
vinstringrequired |
17-character Tesla VIN from list vehicles. |
Latest telemetry snapshot for a vehicle, sourced from Tesla Fleet Telemetry and stored by the Teslita consumer daemon. Expect updates every few seconds while the vehicle is driving or charging, and sparse updates while parked.
If no telemetry has been received yet for this vehicle
(e.g. telemetry provisioning is still pending),
data is null and a human-readable
reason is included.
last_signal_attimestamp | When Tesla last sent us anything for this vehicle. |
charging_statestring | null | Idle, Charging, Complete, Stopped, … |
battery_levelinteger | null | State of charge, 0–100. |
charge_limit_socinteger | null | User-set charge limit, 0–100. |
energy_remaining_kwhnumber | null | Best available estimate of usable battery energy. |
odometer_kmnumber | null | Full odometer reading. |
location.latitudenumber | null | Signed decimal degrees. |
location.longitudenumber | null | Signed decimal degrees. |
gearstring | null | ShiftStateP, ShiftStateD, ShiftStateR, ShiftStateN. |
vehicle_speed_kmhnumber | null | Instantaneous speed in km/h. |
A yes/no derived by haversine distance between the vehicle's last-known position (from Fleet Telemetry) and the user's configured home coordinates (from settings). No Tesla call, no wake-up. Under the default per-key rate limit with no per-endpoint cap.
The threshold is the user's home_radius_m, or
150 m by default when none is configured —
enough to cover a driveway plus GPS jitter without catching
the neighbour. distance_m is always included so
you can apply your own tolerance if 150 m doesn't fit.
If the user hasn't set a home location at all, data
is null and reason explains why.
Similarly if no telemetry has been received for the vehicle.
at_homeboolean | true when distance_m ≤ home_location.radius_m. |
distance_minteger | Great-circle distance in metres between vehicle and home, rounded to the nearest metre. |
vehicle_locationobject | latitude and longitude from the last telemetry signal. |
home_locationobject | Configured latitude, longitude, radius_m, and radius_source ("configured" or "default"). |
is_freshboolean | true when the telemetry position is within 5 minutes old. A stale true may mean the car is parked at home and sleeping (which is normal). |
Most recent pack-health sample for a vehicle: brick balance, module temperatures, isolation resistance, drive-unit states, and tyre pressures. Sampled hourly when the vehicle is reporting.
battery.imbalance_mvinteger | null | Max − min brick voltage, in millivolts. A quick proxy for cell balance — under 30 mV is healthy. |
battery.module_temp_max_cnumber | null | Hottest module temperature at sampling time. |
battery.isolation_resistance_ohminteger | null | HV isolation, ohms. Dropping values can signal insulation degradation. |
drive_unitsobject | Per-drive-unit inverter state: front, rear, rear_left, rear_right. Nulls indicate absent units. |
tpms_barobject | Tyre pressure in bar, one field per corner. |
Historical pack-health samples ordered oldest-first within the
range. Defaults return up to 500 rows; the hard cap is 2000.
Filter with from/to for longer windows.
fromstringoptional | ISO-8601 or YYYY-MM-DD. Inclusive lower bound on sampled_at. |
tostringoptional | ISO-8601 or YYYY-MM-DD. Inclusive upper bound on sampled_at. |
limitintegeroptional | Default 500, max 2000. |
Completed trips, newest first, cursor-paginated. Active (in-progress) trips are not included here — they show up on vehicle state while they're running, and appear here once they end.
vinstringoptional | Restrict to one vehicle. |
fromstringoptional | ISO-8601 or YYYY-MM-DD. Inclusive lower bound on started_at. |
tostringoptional | ISO-8601 or YYYY-MM-DD. Inclusive upper bound. |
limitintegeroptional | Default 50, max 200. |
cursorstringoptional | Value of next_cursor from the previous response. |
data[].idstring | Opaque trip identifier. Use in retrieve a trip and trip route. |
data[].started_attimestamp | When the vehicle shifted out of Park. |
data[].ended_attimestamp | When the vehicle returned to Park and stayed there. |
data[].distance_kmnumber | Path distance, not straight-line. |
data[].energy_used_kwhnumber | null | Derived from start/end EnergyRemaining snapshots; null when inputs are unreliable. |
data[].efficiency_wh_per_kminteger | null | Computed only when both energy and distance are usable. |
next_cursorstring | null | Pass back as cursor for the next page. null means you've reached the end. |
Returns a single trip. Same fields as an entry from
list trips, wrapped in a data
envelope. A trip owned by a different user, or an unknown id,
returns 404 not_found.
GPS waypoints for a single trip, ordered by recorded_at
ascending. These are the samples Teslita collects from Fleet
Telemetry and stitches together to form the path. Any individual
field on a waypoint can be null — the vehicle doesn't
publish every signal on every tick.
Point density varies with speed and signal type. Expect sub-second spacing while moving and tens of seconds while idling at a light. Downsample client-side if you need a fixed cadence.
Charging sessions from all sources — home, destination, and
Supercharger — merged into one timeline, newest first,
cursor-paginated. Each session's type classifies
where it happened.
vinstringoptional | Restrict to one vehicle. |
typestringoptional | One of home, supercharger, other. |
fromstringoptional | Inclusive lower bound on started_at. |
tostringoptional | Inclusive upper bound on started_at. |
limitintegeroptional | Default 50, max 200. |
cursorstringoptional | From previous next_cursor. |
data[].session_idstring | Tesla's id for supercharger sessions, or a synthetic tlm_* id for telemetry-reconstructed home/destination sessions. |
data[].energy_added_kwhnumber | null | Battery-side energy added. |
data[].energy_grid_kwhnumber | null | Grid-side energy pulled (available on home/destination where a meter is present). |
data[].costobject | Native amount plus ISO currency. amount is null when Tesla hasn't invoiced and no home-price estimate is configured. |
data[].invoice_availableboolean | true if a Tesla-issued PDF can be fetched via invoice PDF. |
A single session. Shape matches an entry from
list sessions, wrapped in a
data envelope. session_id values from
Tesla can contain characters that need URL-encoding — encode
them before interpolating into the path.
Power, battery level, and energy-added over the life of a charging session. Samples come from the telemetry consumer daemon and are ordered oldest-first, making the response directly consumable as chart input.
Supercharger sessions imported from Tesla's history endpoint
don't carry per-sample telemetry; this endpoint returns an empty
samples array for those.
Supercharger sessions that have a Tesla-issued PDF invoice
available. Only these sessions have retrievable PDFs — home
sessions are Teslita-estimated, not Tesla-invoiced. Each entry
carries a pdf_url pointing at the binary download
endpoint.
vinstringoptional | Restrict to one vehicle. |
limitintegeroptional | Default 50, max 200. |
cursorstringoptional | From previous next_cursor. |
Streams the Tesla-issued Supercharger invoice PDF as binary
application/pdf. The first fetch may round-trip to
Tesla to retrieve the PDF; subsequent fetches are served from a
local gzip cache in under 50ms.
Every call appends a row to the invoice download audit log so the account owner can see who downloaded what. This applies to API-key downloads and UI downloads equally.
If the session has no Tesla invoice on file, the response is
404 not_found.
A focused view of what the vehicle is doing right now: charging state, SoC, power, projected time-to-full. Backed by the local Fleet Telemetry cache — this endpoint never calls Tesla and never wakes the car, so it's safe to poll regularly.
Under the default per-key rate limit (120/min), with no
per-endpoint cap. If the car is asleep and therefore not
publishing telemetry, is_fresh becomes
false and data_age_seconds tells you
how stale the view is.
charging_statestring | null | Charging, Idle, Starting, Stopped, Complete, Disconnected, NoPower. |
battery_levelinteger | null | State of charge, 0–100. |
charge_limit_socinteger | null | User-set charge limit, 0–100. |
energy_added_kwhnumber | null | Energy added during the current session (resets on plug-in). |
charger_power_kwnumber | null | Instantaneous charging power. |
charger_voltagenumber | null | Charger voltage. Low values (≈1 V) are Tesla's "not connected" sentinel, not a real reading. |
time_to_full_mininteger | null | Estimated minutes to reach charge_limit_soc, from the car's own projection. |
fast_charger.presentboolean | null | Whether a DC fast charger is currently connected. |
data_age_secondsinteger | null | Seconds since the car last sent us telemetry. |
is_freshboolean | true when data_age_seconds is within 5 minutes. Used internally by start/stop to decide whether to short-circuit. |
A dedicated yes/no for "is the charge cable connected to the car right now?". Computed from the same Fleet Telemetry cache as charging status — no Tesla call, no wake-up, safe to poll. Under the default per-key rate limit with no per-endpoint cap.
Under the hood we check both charging_state and
detailed_charge_state for any variant of
Disconnected, because Tesla sometimes updates one
slightly before the other during a state transition.
plugged_in is null only when both
state fields are missing (no telemetry yet).
plugged_inboolean | null | true when the car is physically connected to a charger (including idle / stopped / complete states while plugged in). null when no telemetry has been received. |
at_homeboolean | null | Whether the car is currently inside its configured home geofence — useful for distinguishing "plugged in at home" from "plugged in at a public charger". null when the home location isn't configured or the vehicle hasn't reported a position. See at-home for distance + coordinates. |
charging_statestring | null | Same value as in charging status. Surfaced so callers can distinguish plugged-but-idle from plugged-and-charging. |
detailed_charge_statestring | null | Tesla's more granular enum variant. |
is_freshboolean | true when data_age_seconds ≤ 300. |
Triggers an incremental Supercharger-history sync for one
vehicle. Teslita asks Tesla for any sessions not already in its
database and persists them. The operation is idempotent:
running it repeatedly against a quiet account returns
inserted: 0, updated: 0.
Rate limit: 24 requests per vehicle per 24h. This sits alongside (and below) the global 120-per-minute per-key cap — every call proxies Tesla's fleet API, which is expensive upstream and itself rate-limited. The counter is keyed on the user + VIN, not the API key, so rotating keys doesn't reset it. Averaged out, 24/day is roughly one sync per hour — well above any realistic integration cadence.
Home and destination charging are assembled live from Fleet Telemetry and do not flow through this endpoint. Only supercharger sessions go through here.
vinstringrequired |
17-character Tesla VIN. |
totalinteger | Total number of sessions Tesla returned (including ones we already had). |
insertedinteger | Sessions newly persisted. |
updatedinteger | Existing sessions whose fields changed (e.g. late invoice arrival). |
forbidden403 | Key lacks the write scope. |
tesla_not_connected409 | User has no linked Tesla account. |
upstream_error502 | Tesla's history endpoint failed. |
Asks the vehicle to start charging. Requires that the car is plugged in and not already charging. Tesla will wake the car automatically if it is asleep — expect the call to take up to ~60 seconds in that case.
Before hitting Tesla's API, we consult the local Fleet
Telemetry cache. If data_age_seconds ≤ 300 and
the cached charging_state already shows
Charging or Starting, the endpoint
returns immediately with result: "already_charging"
— no Tesla call, no wake-up, no rate-limit consumption.
If the cached state shows Disconnected, we fail
fast with 409 not_plugged_in for the same reasons.
Only when the telemetry is stale or the state is ambiguous do
we fall through to a signed Tesla command. The
source field in the response tells you which path
was taken.
Rate limit: 24 commands per vehicle per 24h, shared
with charging/stop.
Only calls that actually reach Tesla consume a slot —
short-circuited calls are free. Keyed on user_id + vin
so rotating API keys does not reset the counter.
vinstringrequired |
17-character Tesla VIN. |
commandstring | Always "start". |
resultstring | "issued" when Tesla accepted the command, or "already_charging" when we short-circuited. |
sourcestring | "local_telemetry" or "tesla_api". |
stateobject | Present when source === "local_telemetry": the cached charging status as a convenience for callers. |
forbidden403 | Key lacks the control scope. |
not_plugged_in409 | Fresh telemetry shows charging_state: "Disconnected". |
tesla_not_connected409 | User has no linked Tesla account. |
rate_limited429 | 24-per-day shared start/stop budget exceeded. |
command_failed502 | Tesla rejected the command for a reason we didn't translate to success (e.g. charge port latch failure). |
upstream_error502 | Tesla's API was unreachable or returned HTTP 5xx. |
Asks the vehicle to stop charging. Mirror of charging/start — same short-circuit strategy, same 24-per-day budget, same return shape.
If fresh local telemetry shows the car is not currently
charging (any state other than Charging or
Starting), the endpoint returns
already_stopped without calling Tesla. Otherwise
it sends a signed charge_stop command.
Rate limit: 24 commands per vehicle per 24h, shared with charging/start. Start and stop pull from the same bucket — 24 Tesla calls per vehicle per day total, not 24 of each.
commandstring | Always "stop". |
resultstring | "issued" or "already_stopped". |
sourcestring | "local_telemetry" or "tesla_api". |