Skip to content

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.

vehicles:read

Vehicle metadata and device listings.

positions:read:live

The single most recent position fix — the most sensitive read in the product.

positions:read:history

Bucketed position history, speed alerts, and mileage reports.

alerts:read

The generic alert-event feed (currently: speed alerts; more alert types land here over time).

geofences:read

The organisation's geofence definitions.

geofences:write

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.

drivers:read

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.

GET/api/v1/vehiclesrequiresvehicles:read

List vehicles visible to the caller.

Response: Vehicle[]

GET/api/v1/vehicles/{id}requiresvehicles:read

A single vehicle by id. 404 if it doesn't exist or isn't visible to this token.

Response: Vehicle

GET/api/v1/vehicles/{id}/devicesrequiresvehicles:read

Devices attached to a vehicle.

Response: Device[]

GET/api/v1/vehicles/{id}/positionrequirespositions:read:live

The vehicle's single most recent position fix — "where is this vehicle right now".

Response: { position: Position | null }

GET/api/v1/vehicles/{id}/historyrequirespositions:read:history

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[] }

GET/api/v1/vehicles/{id}/trackrequirespositions:read:history

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[] }

GET/api/v1/vehicles/{id}/alertsrequirespositions:read:history

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[] }

GET/api/v1/vehicles/{id}/mileagerequirespositions:read:history

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? }

GET/api/v1/vehicles/{id}/alert-eventsrequiresalerts:read

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[] }

GET/api/v1/geofencesrequiresgeofences:read

The caller's organisation's geofences, geometry decoded to GeoJSON-shaped numbers.

Response: Geofence[]

GET/api/v1/driversrequiresdrivers:read

The caller's organisation's driver roster.

Response: Driver[]

GET/api/v1/vehicles/{id}/driversrequiresdrivers:read

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" }
400

Malformed request — a bad query param, invalid body, or a bad vehicle/token id.

401

Missing, malformed, unknown, revoked, or expired token.

402

The organisation's subscription entitlement blocks the action.

403

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).

404

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.

409

Valid and authorised, but conflicts with existing state.

500

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.