Skip to content
Travr
Developers

The Travr API

Your vehicles, positions, trips, alerts and zones as a clean REST API, and events pushed to your webhooks. For your own dashboards, your fleet-management or insurance platforms, and partners who integrate with Travr.

Base URL https://api.travr.pro/v1 · version 2026-10-01 · included in Travr Fleet and dealer accounts at no extra cost.

Quick start

Three minutes to your first call

  1. 1. Create a key. Sign in to the Travr Admin console at admin.travr.pro → Developers → New API key. Pick the scopes it needs. The key is shown once — Travr keeps only a fingerprint.
  2. 2. Send it as a bearer token. Authorization: Bearer trv_live_… on every request. The key sees your company and every account under it.
  3. 3. Read. Lists return { data, has_more, next_cursor }; pass cursor back for the next page. Times are ISO 8601 in UTC, distances in km, speeds in km/h.
  4. 4. Subscribe. Add a webhook (console or API) and verify each delivery's signature — see below.
curl https://api.travr.pro/v1/me \
  -H "Authorization: Bearer trv_live_YOUR_KEY"
curl "https://api.travr.pro/v1/vehicles?limit=50" \
  -H "Authorization: Bearer trv_live_YOUR_KEY"
curl "https://api.travr.pro/v1/vehicles/VEHICLE_ID/positions?from=2026-10-01T00:00:00Z&to=2026-10-02T00:00:00Z" \
  -H "Authorization: Bearer trv_live_YOUR_KEY"
curl -X POST https://api.travr.pro/v1/vehicles/VEHICLE_ID/commands \
  -H "Authorization: Bearer trv_live_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"type":"locate"}'

Keys and scopes

Per company, created and revoked by your admins. Scopes limit what a key may read or do. Keys can carry an expiry date. Every key is logged to your audit trail.

Rate limits

600 requests per minute per key. Every response carries X-RateLimit-Limit, -Remaining and -Reset; over the limit you get 429 with Retry-After. Prefer webhooks to polling.

Errors

{ error: { code, message, details? } } with the matching HTTP status: 400 bad request, 401 unauthorised, 403 forbidden (scope or account), 404 not found, 429 rate limited. Quote X-Request-Id when you write to us.

ScopeAllows
vehicles:readVehicles and their last known position, tracker and status
positions:readPosition history, up to 7 days per call
trips:readTrips with distance, duration, speeds and GeoJSON routes
events:readAlerts and events (movement, zones, power, battery, immobiliser…)
geofences:readZones (circles and polygons)
commands:locateAsk a tracker for a fresh fix. Immobilising is never available through the API
webhooks:manageCreate and manage webhooks through the API (they can also be set up in the console)
Webhooks

Events, pushed to you

One signed JSON POST per event, retried for six hours if your endpoint is down. Up to ten webhooks per company; each picks the events it wants.

trip.startedA vehicle set off
trip.endedA trip closed — distance, duration, start and end
alert.raisedAny alert: movement without key, power cut, low battery, overspeed, SOS, tracker offline…
geofence.enteredA vehicle entered a zone
geofence.exitedA vehicle left a zone
vehicle.immobilisedThe immobiliser engaged
vehicle.releasedThe immobiliser was released
command.completedA command you sent finished (acknowledged, failed or expired)
  • Answer 2xx within 10 seconds; do the work afterwards.
  • Retries after 1, 5, 15, 60 and 360 minutes; 25 failures in a row switch the webhook off (switch it back on in the console).
  • Deliveries are at-least-once: ignore an id you have already processed.
  • Headers: X-Travr-Event, X-Travr-Delivery, X-Travr-Signature.

Create one through the API (or in the console):

curl -X POST https://api.travr.pro/v1/webhooks \
  -H "Authorization: Bearer trv_live_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/travr","events":["trip.ended","alert.raised"]}'

What arrives:

{
  "id": "8b04b737-0a8f-44fe-a3fd-6114e1704e2b",
  "event": "trip.ended",
  "created_at": "2026-10-01T11:03:23.013Z",
  "attempt": 1,
  "data": {
    "vehicle": { "id": "…", "name": "CK0202", "registration": "CK0202", "company_id": "…" },
    "trip": { "id": "…", "started_at": "…", "ended_at": "…", "distance_km": 12.4, "duration_s": 1860,
              "start": { "latitude": 51.52, "longitude": -0.26, "address": null },
              "end":   { "latitude": 51.53, "longitude": -0.20, "address": null } }
  }
}

Verify the signature — t=<unix seconds>,v1=<hex HMAC-SHA256 of "t.body" with your webhook secret> — on the raw request body, before parsing it:

import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyTravr(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(signatureHeader.split(',').map((kv) => kv.split('=')));
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!(age < 300)) return false;                       // older than five minutes: replay
  const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  return expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
Reference

Endpoints

Generated from the OpenAPI document. Path parameters are UUIDs; list endpoints accept limit and cursor.

Account

get/me— The key and its company

Responses: 200 OK · 401

get/companies— Companies the key can see

Responses: 200 OK

Vehicles

get/vehicles— List vehicles

Vehicles in scope with their tracker and last known position. Scope vehicles:read.

company_idstring (uuid)Restrict to one company in scope (default all)
statusactive | inactive | service_mode | suspended | decommissioned
type
groupstringExact group name
registrationstringRegistration / plate (spaces ignored, case-insensitive)
qstringFree text over name, registration and VIN
updated_sincestring (date-time)Only vehicles changed after this time
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK · 401 · 403

get/vehicles/{id}— One vehicle

Responses: 200 OK · 404

Positions

get/vehicles/{id}/positions— Position history

Every fix the tracker reported in the window, oldest first by default. The window may be at most 7 days (default: the last 24 hours); up to 1000 fixes per page. Scope positions:read.

fromstring (date-time)
tostring (date-time)
orderasc | desc (default asc)
limitinteger (default 200)
cursorstringnext_cursor from the previous page

Responses: 200 OK · 400

Trips

get/trips— List trips

Trips started in the window (default the last 30 days), newest first. Scope trips:read.

company_idstring (uuid)Restrict to one company in scope (default all)
fromstring (date-time)
tostring (date-time)
statusopen | closed
includerouteroute adds the GeoJSON route to every trip
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK

get/vehicles/{id}/trips— Trips of one vehicle
fromstring (date-time)
tostring (date-time)
statusopen | closed
includeroute
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK

get/trips/{id}— One trip, with its route
includenonenone leaves the route out

Responses: 200 OK · 404

Events

get/events— Alerts and events

Events raised in the window (default the last 7 days), newest first. Scope events:read.

company_idstring (uuid)Restrict to one company in scope (default all)
vehicle_idstring (uuid)
typestringComma-separated list of event types
severityinfo | warning | critical
acknowledgedboolean
fromstring (date-time)
tostring (date-time)
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK

Geofences

get/geofences— List zones (geofences)
company_idstring (uuid)Restrict to one company in scope (default all)
activeboolean
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK

get/geofences/{id}— One zone

Responses: 200 OK · 404

Commands

post/vehicles/{id}/commands— Ask the tracker for a fresh position

Queues a locate command for the vehicle's tracker and answers 202 at once; poll GET /commands/{id} or subscribe to the command.completed webhook. A locate already pending for the same vehicle in the last two minutes is returned instead of a new one (reused: true). Scope commands:locate. Immobilise and release answer 403.

Responses: 202 Queued · 403 · 409 The vehicle has no tracker

get/commands/{id}— Command status

Responses: 200 OK · 404

Webhooks

get/webhooks— List webhooks

Responses: 200 OK

post/webhooks— Create a webhook

The response includes the signing secret — the only time it is returned by the API (it stays visible in the Admin console). At most 10 webhooks per company. Scope webhooks:manage.

Responses: 201 Created · 400 · 409 Limit reached

get/webhooks/{id}— One webhook

Responses: 200 OK · 404

patch/webhooks/{id}— Update a webhook

Any of url, events, description, active. Switching a webhook back on resets its failure count.

Responses: 200 OK · 400

delete/webhooks/{id}— Delete a webhook

Responses: 204 Deleted · 404

post/webhooks/{id}/test— Send a test event

Queues a webhook.test delivery; it goes out within a minute.

Responses: 202 Queued · 409 The webhook is switched off

get/webhooks/{id}/deliveries— Recent deliveries
limitinteger (default 50)
cursorstringnext_cursor from the previous page

Responses: 200 OK

Questions, a partner integration, or something missing? Write to sales@travr.pro. Immobilising a vehicle is deliberately not in the API: it stays behind a person and a PIN in the Travr dashboard and app.

Next step

See your vehicles on the map this week

Fifteen minutes on a call with your vehicles on the screen, or run Travr Fleet on your own fleet for free before you decide. No sales script, no card, no contract.

A person replies within two working days — usually the same day.