A documented, published interface.
What your technical team needs in order to read the fleet and write to it from your own systems: the full specification is published and readable now, and the contract is fixed and exported in a standard format.
One REST API, fully described.
The platform publishes a single REST API under /api/v1, and every operation on it is described in an OpenAPI file published on the internet — not a hand-written excerpt page that drifts behind the code.
- Published paths — 609 paths
- Described operations — 759 operations, each with a stable identifier
- Interface version — v1 — carried in every path
- Format — OpenAPI 3 · JSON request and response bodies
One key, in a request header.
Every programmatic call carries your organization's key in the X-API-Key header. The key belongs to the organization and to its permissions, and it sees nothing beyond its own data.
- The header: X-API-Key — on every protected request.
- Keys are issued from inside the platform, by an account that holds the manage-keys permission.
- The key value is shown once, at creation, and is never retrievable afterwards.
- Revocation is immediate from the same screen, and every issue and revoke is written to the audit trail.
- Programmatic access is available on the Pro and Enterprise plans.
Every list is paginated, with a declared ceiling.
All list endpoints accept the same parameters, and every response carries the total, the page and the limit — so there is nothing to guess about where the data ends.
- page — Page number, starting at 1
- limit — Rows per page — default 20, maximum 100
- sort — Sort field, from a per-endpoint allowed set
- order — asc or desc
Four steps, each with a real request and a real response.
No need to ask us what the answer looks like. These are four real calls against the live platform, in the order you would actually make them, with the values replaced to protect our customers' data — but the shape is exactly what comes back.
1. Authenticate
Login returns a short-lived bearer token (a JWT). Your organization is carried inside that token and read from nowhere else — never from the request body, the URL, or a header.
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "owner@example.com",
"password": "••••••••"
}
{
"success": true,
"data": {
"access_token": "eyJhbGciOi...",
"refresh_token": "eyJhbGciOi..."
}
}
2. Read a page of vehicles
The token goes in the Authorization header on every call after this. The values below are entirely replaced; only the shape matches what a real account gets back.
GET /api/v1/vehicles?page=1&limit=2
Authorization: Bearer <access_token>
{
"success": true,
"data": [
{
"id": 1001,
"tenant_id": 9001,
"imei": "000000000000001",
"name": "DEMO-001",
"name_ar": "مثال-001",
"saudi_plate": "0000 AAA",
"vehicle_class": "van",
"make": "Example",
"model": "Model",
"year": 2024,
"fuel_type": "diesel"
}
],
"meta": { "total": 2, "page": 1, "limit": 2 }
}
3. Read the usage-limit headers
The same response above already carries your counter's state at that instant — no extra call, and no number published here (the ceiling is set per organization, as the next section explains).
— (on any successful response from the step above)
X-RateLimit-Limit: <your organization's ceiling>
X-RateLimit-Remaining: <what is left right now>
X-RateLimit-Reset: <Unix timestamp>
# and once you exceed it:
HTTP/1.1 429 Too Many Requests
Retry-After: <seconds>
4. Ask what the hardware can do
Each device family's capabilities are published by name — and so is the full truth with them: every verb today carries sendable: false, because the platform refuses to send a command encoding it has never verified against real hardware. That is a deliberate safety position, not a gap we are hiding.
GET /api/v1/devices/capabilities
Authorization: Bearer <access_token>
{
"success": true,
"data": {
"allow_unverified_commands": false,
"families": [
{
"name": "family_1",
"verbs": [
{ "verb": "get_info", "status": "documented", "sendable": false },
{ "verb": "immobilize", "status": "documented", "sendable": false }
]
}
]
}
}
The limits are declared in the response headers.
No trial and error is needed to learn what you have left: every response carries the state of your counter at that moment.
- X-RateLimit-Limit — The ceiling for the current window
- X-RateLimit-Remaining — What is left inside it
- X-RateLimit-Reset — When the counter resets
The platform calls your system when something happens.
Instead of your system asking the platform every minute, you register one address (a webhook) and the event reaches you the moment it occurs. The list of subscribable events is served by the product itself, so it cannot drift behind the code:
- trip.completed — A trip finished and was recorded
- geofence.entered — A vehicle entered a zone
- geofence.exited — A vehicle left a zone
- alert.created — A new alert from an active rule
- device.offline — A vehicle's device stopped reporting
- alert.escalation.<template_key> — The alert-escalation family — the suffix is your own notification template key
Open the specification, then run it.
The interactive specification page is open to read right now, and it lays out every operation with its parameters and responses. The specification file's own address imports straight into any API client, so the whole call collection assembles itself without you writing a line.
Reading is open to anyone; running calls against your organization's data needs a key.
Is the interface read-only, or can we write too?
Do you ship a client library for our language?
How do we know the documentation matches what actually runs?
Can one key see another organization's data?
Your fleet deserves this clarity.
Start with a demo on real data from the platform itself — we reply within one business day.
