The fleet & telematics data plane for your integration.
A public REST API for reading and acting on fleets, vehicles, drivers, journeys, live positions, video and device commands. Built for third-party developers.
From credentials to first call in four steps.
Every endpoint requires an OAuth2 client-credentials bearer token carrying the scopes it needs. There is no user login: this is a server-to-server integration.
Get a client_id and client_secret for your integration from
your Haloniq administrator. Credentials are scoped to your organization and its
descendant tenants.
Exchange your credentials at the identity token endpoint using the
client_credentials grant. Ask only for the scopes you need.
curl -X POST https://identity.haloniq.com/connect/token \
-d grant_type=client_credentials \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope="thirdparty.api.fleets_read thirdparty.api.vehicles_read"
Send the returned access_token as a Bearer header. Responses
are snake_case JSON; list endpoints are cursor-paginated.
curl https://developer.haloniq.com/v1/fleets \
-H "Authorization: Bearer $ACCESS_TOKEN"
Browse every resource, schema and example in the Scalar reference, or pull the machine-readable OpenAPI 3.1 document to generate a client SDK.
One scope per resource and action.
Requests are authorized by OAuth2 scopes. Read and write are granted
separately, and device commands are split so wake-up can be allowed without reboot.
A missing scope returns 403.
| Scope | Grants |
|---|---|
| Read | |
thirdparty.api.organizations_read | Read organizations across your tenant hierarchy. |
thirdparty.api.fleets_read | Read fleets and their membership. |
thirdparty.api.vehicles_read | Read vehicles and vehicle telemetry. |
thirdparty.api.drivers_read | Read driver records. |
thirdparty.api.devices_read | Read devices, device telemetry and media items. |
thirdparty.api.events_read | Search telematics events over a date window. |
thirdparty.api.journeys_read | Query completed journeys for a vehicle, fleet or device. |
thirdparty.api.live_positions_read | Read real-time vehicle positions. |
thirdparty.api.webhooks_read | Read webhook subscription configuration. |
| Write | |
thirdparty.api.fleets_write | Create and update fleets. |
thirdparty.api.vehicles_write | Create and update vehicles. |
thirdparty.api.drivers_write | Update driver records. |
thirdparty.api.devices_write | Assign and unassign devices. |
thirdparty.api.video_requests_write | Request video and media uploads from devices. |
thirdparty.api.live_streams_write | Start live video streams from device cameras. |
thirdparty.api.playback_sessions_write | Start video playback sessions. |
thirdparty.api.webhooks_write | Create and manage webhook subscriptions. |
| Device commands | |
thirdparty.api.device_commands_reboot | Send a reboot command to a device. |
thirdparty.api.device_commands_wake_up | Send a wake-up command to a device. |
What the API exposes.
A versioned surface over the platform's fleet and telematics data
plane, all under /v1.
Read and manage your fleet structure and vehicle records, including per-vehicle telemetry.
Read and update driver records across your organization.
Query completed journeys over a date window for a vehicle, fleet or device.
Poll real-time vehicle positions across the fleets you can see.
Search telematics events with narrowing filters and a date window.
List device media with signed download URLs and request new video uploads.
Start live streams and playback sessions from device cameras.
List devices, read telemetry, assign to vehicles, and reboot or wake them remotely.
Traverse your tenant's organization hierarchy and descendants.
Subscribe to CloudEvents 1.0 messages the platform POSTs to your endpoints.
Push, not poll: CloudEvents delivered to your endpoint.
Subscribe once and the platform POSTs a
application/cloudevents+json envelope to your endpoint whenever something
happens on your fleet. Every message follows the CloudEvents 1.0 specification, so
the envelope is identical across all topic types. Only the data payload
changes with the event type.
The CloudEvents envelope
| Field | Type | Notes |
|---|---|---|
id | string | Required. Producer idempotency key (event / alarm id, or hardwareId:utc). De-duplicate on this. |
source | uri-reference | Required. Origin of the event, e.g. /brigade/events, /brigade/livetrack. |
type | string | Required. One of the five topic types below. Discriminates the data schema. |
specversion | string | Required. Constant "1.0". |
time | date-time | Device wire time (not processing time). |
datacontenttype | string | Media type of data; defaults to application/json. |
subject | string | Device / hardware id. |
dataschema | uri | Schema URI for the data payload. |
data | object | The type-specific payload, one of the five records below. |
Topic types & payloads
Five outbound topic types. The CloudEvents type discriminates
the schema. Payload property names are camelCase, unlike the snake_case REST API.
| CloudEvents type | Fires on | Payload highlights |
|---|---|---|
live.gps | Each live GPS fix (topic live_gps) | hardwareId, latitude, longitude, heading, speed, utc, invalidGps |
journey.closed | A journey completes (topic journeys) | journeyId, hardwareId, startUtc / endUtc, start & end lat-long, distanceMeters, durationSeconds |
alarm.triggered | A device raises an alarm (topic alarms) | id, hardwareId, triggerOn, alarmKey, locations[], speedPoints[], headingPoints[] |
event.generic | A telematics event (topic events) | eventId, hardwareId, triggerUtc, eventTypes[], eventCategories[], isAccident, locations[], address, vehicleId |
media.ready | Requested media is ready (topic media) | mediaId, hardwareId, fileName, mimeType, channel, downloadUrl (time-limited SAS) |
Delivery transports
The delivery plane fans each event out to the subscriber's chosen transport. Through the Developer API today you subscribe over HTTPS callback; the Event Hub and Kafka transports are platform capabilities provisioned out-of-band (roadmap for self-serve).
| Transport | Via Developer API | Best for |
|---|---|---|
HttpCallback | Yes, the default and only self-serve transport. POSTs the CloudEvents envelope to your HTTPS URL. | Any subscriber with an HTTPS endpoint. |
AzureEventHub | Platform / roadmap, provisioned out-of-band. | High-volume Azure-native streaming into your own Event Hub. |
Kafka | Platform / roadmap, provisioned out-of-band (SASL/SSL). | Streaming into your own Kafka cluster. |
Delivery headers & retries
| Header | Meaning |
|---|---|
X-Webhook-Key | Your organization's shared auth key, sent verbatim so you can authenticate the sender. Declared in the OpenAPI webhooks doc. |
X-Delivery-Attempt | 1-based attempt number; a value >1 means a retry after a prior non-2xx / timeout. De-duplicate against the envelope id. Declared in the OpenAPI webhooks doc. |
Idempotency-Key | Stable per (event, destination) delivery id. Use it for exactly-once handling. |
traceparent | W3C trace context, when present. |
Optional per-destination custom headers exist at the delivery-worker level but are not settable through the Developer API today.
Authentication is a shared key, not a signature. Each delivery carries your
X-Webhook-Key verbatim so you can authenticate the sender. There is
no HMAC and no payload signing today, so verify the shared key on receipt and
rotate it via the regenerate-auth-key endpoint.
Subscribing with the webhook-config API
Manage your subscription under
/v1/organizations/{organizationId}/webhook-config. Reads require
thirdparty.api.webhooks_read; every mutation requires
thirdparty.api.webhooks_write. Optimistic concurrency uses
ETag / If-Match (stale → 412); secrets are never
returned by GET (only an auth_key_hint).
| Method & path | Scope | Purpose |
|---|---|---|
GET /webhook-config | webhooks_read | Read the config; 404 if none. Secrets redacted to auth_key_hint. |
PUT /webhook-config | webhooks_write | Create-or-replace the whole config. If-Match required once it exists. |
PATCH /webhook-config | webhooks_write | Enable / disable delivery. |
DELETE /webhook-config | webhooks_write | Delete the config. 204. |
POST /webhook-config/regenerate-auth-key | webhooks_write | Rotate the auth key; the raw key is returned exactly once. |
PUT /webhook-config/topics/{topicType} | webhooks_write | Upsert one topic (max 25). {topicType} = events | alarms | media | live_gps | journeys. |
DELETE /webhook-config/topics/{topicType} | webhooks_write | Remove one topic. The last remaining topic cannot be removed (409). |
# register an HTTPS callback for closed journeys
curl -X PUT https://developer.haloniq.com/v1/organizations/$ORG_ID/webhook-config/topics/journeys \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"type":"journeys","is_enabled":true,"delivery":{"url":"https://your-app.example.com/hooks/haloniq"}}'
Callback URLs must be absolute HTTPS, ≤2048 chars, and not loopback,
link-local or private ranges (an SSRF guard blocks localhost, 127.0.0.0/8,
10/8, 172.16/12, 192.168/16, 169.254/16,
::1). Violations return 422 webhook.ssrf_blocked.
Generate a typed client from the OpenAPI 3.1 document.
The API publishes a machine-readable
OpenAPI 3.1 document at /openapi/v1.json. Point a
generator at it and get a fully typed client with no hand-written HTTP. Two
generators are supported: Microsoft Kiota (the partner-SDK generator, multi-language)
and NSwag (a dependency-light single-file C# client).
Microsoft Kiota: multi-language typed client
Kiota emits a request-builder tree
(client.V1.Fleets[id].GetAsync()) and generates for C#, Java, Go, Python,
TypeScript, PHP and Ruby from the same spec. OpenAPI 3.1 is detected natively, so no flag is needed.
# freeze the OpenAPI 3.1 document as the generation input
curl -fsSL https://developer.haloniq.com/openapi/v1.json -o v1.json
# one-time: install the generator
dotnet tool install --global Microsoft.OpenApi.Kiota
# generate the typed C# client (multi-file, request-builder tree)
kiota generate \
-l CSharp \
-d v1.json \
-o ./sdk/kiota \
-n Haloniq.DeveloperApi.Client \
-c DeveloperApiClient \
--clean-output
NSwag: single-file C# client
NSwag emits one .cs file with flat methods
(client.GetFleetAsync(id)). Pin a 3.1-capable 14.x build, because 13.x
mishandles the 3.1 type-arrays.
# one-time: install a 3.1-capable build (pin 14.7.1)
dotnet tool install --global NSwag.ConsoleCore --version 14.7.1
# emit a single-file C# client
nswag openapi2csclient \
/input:v1.json \
/classname:DeveloperApiClient \
/namespace:Haloniq.DeveloperApi.Client \
/output:DeveloperApiClient.cs
Which to choose
| Dimension | Kiota | NSwag |
|---|---|---|
| Output shape | Many files: models plus a request-builder tree | One .cs file |
| Call style | Fluent: client.V1.Fleets[id].GetAsync() | Flat: client.GetFleetAsync(id) |
| Languages | C# / Java / Go / Python / TypeScript / PHP / Ruby | C# / TypeScript |
| Serialization | System.Text.Json (pluggable) | Newtonsoft.Json by default (System.Text.Json opt-in) |
| Dependencies | Microsoft.Kiota.Bundle | Just Newtonsoft.Json (none with System.Text.Json) |
| OpenAPI 3.1 | Native, no flag | Needs a 14.x build |
Rule of thumb: ship a partner SDK with Kiota when you need more than one
target language: one spec generates C#, Java, Python, Go and TypeScript from the
same tool. Reach for NSwag when you want a dependency-light, drop-in single C# file
for a quick smoke call, a console harness, or an independent cross-check of the contract.
Both parse the 3.1.1 document; verify by running dotnet build on
the generated project and confirming 0 errors.
Reference output
A reference C# SDK, the frozen spec and the regeneration scripts are kept
in this repository under .workspace/developer-api-handoff/sdk/, in the
recommended layout:
sdk/
├── openapi/v1.json # frozen OpenAPI 3.1 doc = generation input
├── kiota/ # Kiota multi-file client (Haloniq.DeveloperApi.Client)
│ ├── kiota-lock.json # enables `kiota update` re-generation
│ └── Haloniq.DeveloperApi.Client.csproj
└── nswag/
└── DeveloperApiClient.cs # single-file NSwag client
Re-generate after a spec change with kiota update (it reads
kiota-lock.json) or by re-running the NSwag command above.