Developers
Read-only REST API · Scoped tokens
Every vehicle, position, and alert you can see in Everia, you can also read programmatically through the same REST API the web app itself uses. Once it's switched on for your organisation, mint a scoped token in Settings → API tokens, pick exactly the scopes and vehicles it needs, and go.
Programmatic access is a hand-enabled add-on, not a self-serve plan feature — get in touch and we'll turn it on for your organisation.
Base URL & auth
Every endpoint below is served from this origin under /api/v1 — for example, the hosted deployment serves it at https://api.dragontech.com.au/api/v1. A self-hosted instance serves the same paths from its own origin.
Authenticate every request with a scoped API token as a bearer credential:
Authorization: Bearer dragonfleet_sk_...
Tokens are shown in full exactly once at creation time and stored hashed thereafter — there is no way to retrieve a lost token; revoke it and issue a new one.
Scopes
A token can only call an endpoint if it was issued with that endpoint's required scope. Vehicle-scoped endpoints (everything under /vehicles/{id}) are further limited to the specific vehicles the token was issued for — re-checked against the issuing user's current access on every request, not just at issuance. Organization-level reads (/geofences, /drivers) return every record in the token's organisation regardless of its vehicle scope.
Vehicle metadata and device listings.
The single most recent position fix — the most sensitive read in the product.
Bucketed position history, speed alerts, and mileage reports.
The generic alert-event feed (currently: speed alerts; more alert types land here over time).
The organisation's geofence definitions.
Reserved vocabulary only — no endpoint currently accepts it. Every geofence mutation route rejects scoped tokens outright (403); this scope exists so the read/write pair is symmetric for a future task that revisits token-scoped writes.
The organisation's driver roster and per-vehicle driver assignments.
No write scope grants a mutation today — issuing, listing, and revoking tokens, and every create/update/delete endpoint in the API, are session-only in v1. A scoped token that calls a mutation route always gets 403.
Endpoints
Every endpoint below also works with a signed-in user's session — this list covers the subset a scoped API token can reach.
List vehicles visible to the caller.
Response: Vehicle[]
A single vehicle by id. 404 if it doesn't exist or isn't visible to this token.
Response: Vehicle
Devices attached to a vehicle.
Response: Device[]
The vehicle's single most recent position fix — "where is this vehicle right now".
Response: { position: Position | null }
Hourly-bucketed position trend data (up to ~1h stale — never the live-tracking path).
Query: from=<ISO 8601>&to=<ISO 8601> (both required, from < to)
Response: { history: HistoryBucket[] }
The full ordered (ts asc), server-decoded position track for a bounded window — the trip-replay path. Server-side even-sampling capped at 3000 points. Requires the advanced_reports plan (a 402 upgrade response otherwise — the one token endpoint that can 402).
Query: from=<ISO 8601>&to=<ISO 8601> (both required, from < to)
Response: { track: TrackPoint[] }
Speed-alert events for a vehicle, newest first, location decoded to lon/lat.
Query: from=<ISO 8601>&to=<ISO 8601> (both optional, both-or-neither)
Response: { alerts: VehicleAlert[] }
Total distance travelled over a window — a billing-ready mileage report.
Query: driver_assignment_id=<uuid> OR (from=<ISO 8601>&to=<ISO 8601>)
Response: { distance_km, positions_count, from, to, driver? }
The generic, decoded alert-event feed across every alert type the platform emits.
Query: from=&to=&type=<alert_type>&limit=<1-500, default 200> (all optional)
Response: { alert_events: AlertEvent[] }
The caller's organisation's geofences, geometry decoded to GeoJSON-shaped numbers.
Response: Geofence[]
The caller's organisation's driver roster.
Response: Driver[]
A vehicle's driver assignments, current and past, newest first, driver joined in.
Response: DriverAssignmentWithDriver[]
Errors
Errors are always a JSON object with an error string, never a raw upstream message:
{ "error": "Token is missing required scope: positions:read:live" }Malformed request — a bad query param, invalid body, or a bad vehicle/token id.
Missing, malformed, unknown, revoked, or expired token.
The organisation's subscription entitlement blocks the action.
Authenticated, but this token's scopes don't cover this endpoint (or it's a mutation route — no write scopes exist for tokens in v1).
The resource doesn't exist, or isn't visible to this token — deliberately conflated so a token can never learn that a vehicle it can't see exists.
Valid and authorised, but conflicts with existing state.
Something failed on our end. Never contains upstream error detail.
Example: curl
curl https://api.dragontech.com.au/api/v1/vehicles/<vehicle-id>/position \ -H "Authorization: Bearer dragonfleet_sk_..."
Example: JavaScript
Plain fetch:
const res = await fetch(
"https://api.dragontech.com.au/api/v1/vehicles/<vehicle-id>/history?from=2026-07-01T00:00:00Z&to=2026-07-08T00:00:00Z",
{ headers: { Authorization: "Bearer dragonfleet_sk_..." } },
);
const { history } = await res.json();Or the typed client this app itself uses (@dragonfleet/api-client on npm within this monorepo — createApiClient accepts a static scoped token exactly the same way it accepts a session token):
import { createApiClient } from "@dragonfleet/api-client";
const client = createApiClient({
baseUrl: "https://api.dragontech.com.au",
getAuthToken: () => "dragonfleet_sk_...",
});
const vehicles = await client.vehicles.list();What's not here yet
There is no machine-readable OpenAPI/Swagger document yet — this hand-written page is the honest v1. The endpoint list above is kept accurate by cross-checking it against the actual route handlers, not generated from them; if that drifts, treat this page as the bug and the route handlers as the source of truth. A generated spec is a reasonable follow-up if real third-party integration demand shows up, not before.