Skip to main content

Messaging & Nearby

Send a free-text message to the mobile app running on a vehicle, and find the mobiles closest to a given point — useful for assigning the nearest unit to a job.

Prerequisites

All endpoints require a valid JWT token, API key, and tenant header. See Authentication.


Send Message

Queue a free-text message to the mobile app of a single vehicle. This is fire-and-forget: a success response means the message was queued, not that it was delivered or read. The mobile app picks it up the next time it polls for messages.

POST/apidev/v1/devices/{vehicle_id}/messages
PermissionAPICLI_DEVICE_MESSAGE
Rate Limit20 req/min (sliding window)
CacheNone

Path Parameters

ParameterTypeRequiredDescription
vehicle_idstringYesVehicle (mobile) unique identifier. Must belong to your tenant.

Request Body

FieldTypeRequiredMax LengthDescription
textstringYes500Message to send to the mobile. Cannot be empty.
pushbooleanNoTrigger a push notification (default true).
Push flag

Today every queued message also fires a push notification, so push: false is accepted but not yet honored. Send true (or omit it) to be future-proof.

Response Fields

FieldTypeDescription
message_idstringIdentifier of the queued message (BigInt as string). May be omitted if the queue did not return one.
vehicle_idstringEcho of the target mobile identifier.
deliverystringAlways "queued" — the message was accepted into the delivery queue. Queued is not the same as delivered or read.

Code Example

curl -s -X POST "https://$TENANT/apidev/v1/devices/1013/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"text": "Head back to base, end of shift."
}'

Example Response

{
"success": true,
"data": {
"message_id": "8472910",
"vehicle_id": "1013",
"delivery": "queued"
},
"meta": {}
}
Mobile without a device

If the vehicle has no active device that can receive messages (no active IMEI), the request fails with 409 CONFLICT. This is different from 404, which means the vehicle does not exist in your tenant. Associate an active device with the mobile before sending it messages.


Nearby Mobiles

Find the mobiles closest to a point, sorted by distance. The search is bounded by a radius (up to 50 km) and can be narrowed by GPS freshness, GPS validity, and vehicle type.

POST/apidev/v1/devices/nearby
PermissionAPICLI_FLEET_DEVICES_READ
Rate Limit20 req/min (sliding window)
CacheNone
Why POST for a read

This is a read in spirit, but it carries a structured body (a point plus filters) that does not fit cleanly into query parameters, and it performs a distance computation. It follows the same convention as the report endpoints, which also accept a POST body.

Request Body

FieldTypeRequiredDefaultDescription
pointobjectYesCenter of the search: { "lat": number, "lng": number }. lat in [-90, 90], lng in [-180, 180].
radius_mnumberYesSearch radius in meters. Min 1, max 50000 (50 km).
limitnumberNo20Maximum results. Min 1, max 100.
only_valid_gpsbooleanNotrueOnly mobiles whose last GPS fix is valid (coordinates present, position valid).
max_age_minnumberNoDrop mobiles whose last GPS fix is older than N minutes. Min 1, max 1440. When omitted, no age limit is applied.
vehicle_typesstring[]NoFilter by vehicle type identifiers (BigInt as strings). Up to 100 values.

Response Fields

The data field is an array of nearby mobiles, ordered by distance ascending.

FieldTypeDescription
vehicle_idstringVehicle (mobile) identifier (BigInt as string).
namestringMobile display name.
platestringLicense plate.
vehicle_type_idstring | nullVehicle type identifier (BigInt as string).
pointobjectLast GPS point: { "lat": number, "lng": number }.
distance_mnumberDistance from the requested point, in meters (rounded).
headingnumber | nullHeading in degrees (0–359), or null when not available.
speednumberSpeed in km/h from the last GPS point.
last_signalstring | nullTimestamp of the last valid GPS fix (without timezone).
valid_gpsbooleanWhether the last GPS fix is valid.
Heading and timestamps

heading is null when no heading is available — never 0, which would mean "due north". last_signal is returned without timezone (e.g., "2026-06-25T14:58:00") and represents the company's configured timezone; display it as-is, without appending Z or converting to UTC.

Code Example

curl -s -X POST "https://$TENANT/apidev/v1/devices/nearby" \
-H "Authorization: Bearer $TOKEN" \
-H "X-API-Key: $APIKEY" \
-H "tenant: $TENANT" \
-H "Content-Type: application/json" \
-d '{
"point": { "lat": -34.9050, "lng": -56.1910 },
"radius_m": 5000,
"limit": 10,
"only_valid_gps": true,
"max_age_min": 30,
"vehicle_types": ["5"]
}'

Example Response

{
"success": true,
"data": [
{
"vehicle_id": "1013",
"name": "Grua 07",
"plate": "ABC 1234",
"vehicle_type_id": "5",
"point": { "lat": -34.9012, "lng": -56.1888 },
"distance_m": 342,
"heading": 270,
"speed": 0,
"last_signal": "2026-06-25T14:58:00",
"valid_gps": true
},
{
"vehicle_id": "1021",
"name": "Grua 12",
"plate": "DEF 5678",
"vehicle_type_id": "5",
"point": { "lat": -34.9100, "lng": -56.1950 },
"distance_m": 820,
"heading": 135,
"speed": 34,
"last_signal": "2026-06-25T14:59:30",
"valid_gps": true
}
],
"meta": {
"total": 2,
"limit": 10
}
}
No results is not an error

If no mobile falls within the radius — or all of them are filtered out by only_valid_gps, max_age_min, or visibility rules — the response is 200 with an empty data array. Each mobile is also subject to the visibility rules of your technical user, so you only see the mobiles that user is allowed to see.

Radius cap

The maximum radius is 50 km. A larger radius_m is rejected with 400 rather than silently clamped, to prevent an accidental scan of the whole fleet.


Errors

See Error Handling for the full reference.

CodeHTTPApplies toDescription
VALIDATION_ERROR400Send Message, NearbyEmpty text; or point out of range, radius_m missing or above 50000, limit above 100.
UNAUTHORIZED401AllMissing, invalid, or expired tenant / Authorization / X-API-Key.
FORBIDDEN403AllUser lacks APICLI_DEVICE_MESSAGE (Send Message) or APICLI_FLEET_DEVICES_READ (Nearby).
NOT_FOUND404Send MessageThe vehicle_id does not exist or does not belong to your tenant.
CONFLICT409Send MessageThe mobile has no active device that can receive messages (no active IMEI).
RATE_LIMITED429AllExceeded 20 req/min.
INTERNAL_ERROR500AllUnexpected server error.