TMS · Developer documentation
ELD Integration API
Build an integration once, and any TMS customer can connect your ELD to their fleet. You host a small REST API that conforms to this spec; TMS polls it on a schedule and maps your data onto the customer's trucks and drivers.
Overview
This is a pull integration. There are no webhooks to send and no credentials of ours to manage — you expose read-only endpoints, and TMS calls them. Each TMS customer enters your base URL and an API key you issue them, then TMS polls your API for four resources:
- Vehicle events — GPS location, odometer, engine hours.
- Driver info — the driver roster (matched to TMS drivers by CDL number).
- Driver state — HOS duty-status changes.
- Documents — certified RODS logs, DVIRs, inspection reports.
You expose one base URL, not one per resource. All paths hang off
it ({baseUrl}/v1/vehicles/events, etc.). A single /v1/capabilities endpoint can tell TMS which of the four you
support. If it is unavailable, TMS defaults to vehicle events and driver information; HOS intervals and
documents remain disabled until explicitly reported.
Authentication
Every request carries a bearer token — the API key the customer pasted into TMS when connecting you.
Reject any request without a valid key with 401 and the error
envelope below.
GET /v1/capabilities HTTP/1.1
Host: eld.your-company.com
Authorization: Bearer <customer-api-key>
Accept: application/jsonVersioning
All endpoints live under a /v1 path prefix. The customer enters
only the root (e.g. https://eld.your-company.com); TMS appends /v1/<resource>. Ship breaking changes under a new prefix
(/v2) rather than mutating /v1.
GET /v1/capabilities · recommended
This endpoint declares which optional resources you support. TMS calls it when a customer connects and caches the result. A missing or unreachable endpoint no longer blocks connection; TMS uses the safe defaults described above. Authentication failures still fail the connection.
| Field | Type | Required | Description |
|---|---|---|---|
| provider | string | required | Human-readable vendor/company name. |
| apiVersion | string | required | API version this vendor implements, e.g. 'v1'. |
| capabilities | object | required | Which optional resources this vendor implements. |
{
"provider": "Acme ELD",
"apiVersion": "v1",
"capabilities": {
"vehicle_events": true,
"driver_info": true,
"driver_state": false,
"documents": false
}
}GET /v1/vehicles/events
A flat list of telemetry events across all vehicles. Include unitNumber when you can — TMS matches vehicles by unit number and creates a local truck when no match exists. Absolute odometerMiles is preferred over inferring distance from GPS.
| Field | Type | Required | Description |
|---|---|---|---|
| vehicleExternalId | string | required | Vendor's own ID for this vehicle. |
| vin | string | null | optional | Vehicle VIN, if known. |
| unitNumber | string | null | optional | Fleet unit number — used to auto-match against TMS trucks. |
| lat | number | required | Latitude, WGS84. |
| lng | number | required | Longitude, WGS84. |
| heading | number | null | optional | Compass heading in degrees, 0-359. |
| speed | number | null | optional | Speed in mph. |
| odometerMiles | number | null | optional | Absolute cumulative odometer reading, in miles. |
| engineHours | number | null | optional | Absolute cumulative engine hours. |
| recordedAt | string | required | ISO 8601 timestamp this event was recorded at the vehicle. |
GET /v1/drivers
The driver roster. licenseNumber (CDL) is the primary matching
key, followed by normalized full name. TMS creates a local driver automatically when no match exists.
| Field | Type | Required | Description |
|---|---|---|---|
| driverExternalId | string | required | Vendor's own ID for this driver. |
| firstName | string | required | Driver first name. |
| lastName | string | required | Driver last name. |
| licenseNumber | string | null | optional | CDL number — used to auto-match against TMS drivers. |
| licenseState | string | null | optional | CDL issuing state. |
| phone | string | null | optional | Driver phone number. |
| string | null | optional | Driver email address. | |
| status | 'active' | 'inactive' | required | Whether this driver is currently active on the vendor side. |
| updatedAt | string | required | ISO 8601 timestamp this record was last updated. |
GET /v1/duty-status
HOS duty-status changes for all drivers in one flat list (not nested per driver, to avoid N+1 polling). Return items in ascending startedAt order — TMS applies intervals sequentially to reconstruct FMCSA clocks. The four status values map
exactly to the FMCSA duty states.
| Field | Type | Required | Description |
|---|---|---|---|
| driverExternalId | string | required | Vendor's own ID for the driver this interval belongs to. |
| status | 'off_duty' | 'sleeper' | 'driving' | 'on_duty' | required | FMCSA duty status at the start of this interval. |
| startedAt | string | required | ISO 8601 timestamp this duty status began. Items MUST be returned in ascending startedAt order. |
| lat | number | null | optional | Latitude at the start of this interval, if known. |
| lng | number | null | optional | Longitude at the start of this interval, if known. |
| truckExternalId | string | null | optional | Vendor's own vehicle ID the driver was operating, if known. |
GET /v1/documents
ELD-originated documents. Provide the bytes inline as contentBase64 for small files, or a bearer-authenticated contentUrl TMS will fetch — exactly one of the two. documentExternalId is used to de-duplicate on re-sync, so keep it
stable.
| Field | Type | Required | Description |
|---|---|---|---|
| documentExternalId | string | required | Vendor's own ID for this document — used to avoid re-ingesting it. |
| driverExternalId | string | null | optional | Related driver, if any. |
| vehicleExternalId | string | null | optional | Related vehicle, if any. |
| docType | string | null | optional | Free-text document type hint, e.g. 'rods_certified' or 'dvir'. |
| fileName | string | required | Original file name, including extension. |
| contentType | string | null | optional | MIME type, e.g. application/pdf. |
| contentUrl | string | null | optional | HTTPS URL to fetch the file bytes from (Bearer-authenticated). Exactly one of contentUrl/contentBase64 must be present. |
| contentBase64 | string | null | optional | Base64-encoded file bytes, for small documents. Exactly one of contentUrl/contentBase64 must be present. |
| createdAt | string | required | ISO 8601 timestamp this document was generated. |
Pagination & incremental sync
Every list endpoint accepts two query params and returns a shared envelope:
since— ISO-8601 timestamp. Return only records at or after it; omit for a full backfill.cursor— opaque string from a prior response'snextCursor.
{
"data": [ /* … page of items … */ ],
"nextCursor": "eyJvZmZzZXQiOjUwfQ==", // null on the last page
"serverTime": "2026-07-08T14:05:00Z" // your clock at response time
} TMS drives it like this: start with since = the last sync's serverTime (omitted on the first run). While nextCursor is non-null, re-request with that cursor (not since).
When it's null, the run is done, and TMS stores the last page's serverTime as the next run's since.
Returning serverTime from your own clock avoids drift between our
clocks.
Errors & rate limiting
Return this envelope for any non-2xx response:
{ "error": { "code": "unauthorized", "message": "Invalid or missing API key" } } 401 unauthorized— bad or missing bearer token.403 forbidden— capability not enabled for this key.404 not_found— unknown resource.429 rate_limited— setRetry-After; TMS backs off and retries.5xx internal— TMS retries with exponential backoff.
Reference server
TMS ships a working, spec-conformant implementation of this API at /api/mock-eld/v1/* (the "Reference mock ELD server" a customer
can connect in Settings → Integrations). Diff your responses against it — same envelope, same field names,
same pagination — to confirm your integration conforms before going live.