External Excavator State
Endpoints for pushing excavator operating states (idle, moving, working) from a telematics or fleet management system into Ditio, and for reading them back.
Endpoints
Section titled “Endpoints”| Method | Route | Description |
|---|---|---|
POST | api/external-excavator-state | Register one state record |
POST | api/external-excavator-state/import | Bulk import (upsert) state records |
GET | api/external-excavator-state/latest-timestamp/{companyId}/{projectId} | Get the sync checkpoint |
POST | api/external-excavator-state/aggregated-data-per-state | Aggregate states for a project and period |
GET | api/external-excavator-state/{id} | Get one state record |
PUT | api/external-excavator-state/{id} | Update one state record (see the note under Update) |
DELETE | api/external-excavator-state/{id} | Delete one state record |
Routes are relative to $DITIO_MASSTRANSPORT_BASE (see
Environments) and need a token with the
masstransportapiv1 scope (see Authentication).
For a walkthrough with examples, see the
Machine Integration guide.
The state record
Section titled “The state record”Each record is one machine’s state at one point in time. A machine stays in that state until its next record. Ditio doesn’t need to know your machines or projects in advance: both are your own ids.
Property names are camelCase in responses and case-insensitive in requests.
| Field | Type | Description |
|---|---|---|
id | string | Ditio’s id for the record (a 24-character hex string). Set by Ditio; leave it out when you create records. |
companyId | string | Your Ditio company id. Send it on every record: the sync checkpoint and the aggregation find records by it. |
externalMachineId | string | The machine’s id in your system. |
externalProjectId | string | The project or site id in your system. This is the {projectId} of the sync checkpoint and the projectId of the aggregation. |
timeStamp | string (date-time) | When the machine entered this state. Send ISO 8601 in UTC with a Z suffix, e.g. 2026-10-02T07:41:12Z. |
state | integer | 0 = Idle, 1 = Moving, 2 = Working. Send the number: a string such as "Working" is rejected with 400. |
geoPoint | object | Optional position of the machine. See geoPoint. |
geoPoint
Section titled “geoPoint”| Field | Type | Description |
|---|---|---|
type | string | Send "Point". Required when you send geoPoint; a missing type, or a value other than "Point" or "Polygon", gives 400. |
coordinates | array of number | [longitude, latitude] in WGS 84 decimal degrees, longitude first. |
accuracy | number | Optional accuracy in metres. Defaults to 0. |
properties | object | Optional { "name": string, "description": string }. |
Responses also include a read-only isValidPoint (boolean) on geoPoint.
Leave out geoPoint entirely if you have no position.
Example
Section titled “Example”{ "companyId": "YOUR_COMPANY_ID", "externalMachineId": "EX-042", "externalProjectId": "SITE-17", "timeStamp": "2026-10-02T07:41:12Z", "state": 2, "geoPoint": { "type": "Point", "coordinates": [10.7522, 59.9139], "accuracy": 5 }}Register Single State
Section titled “Register Single State”POST /api/external-excavator-stateBody: one state record.
Response: 201 Created with the stored record, including its id.
Single registration always inserts a new record: sending the same machine, project and timestamp twice stores two records. Use Bulk Import for anything you may resend.
Bulk Import
Section titled “Bulk Import”POST /api/external-excavator-state/importBody: a JSON array of state records, each with your
companyId. An empty array gives 400.
Response: 200 OK with the submitted array, each item with an id.
Import is an upsert. The key is companyId + externalMachineId +
externalProjectId + timeStamp:
- A new key inserts a record.
- An existing key updates the record’s
stateandgeoPoint. Its storediddoesn’t change, so theidreturned for that item is not the stored one.
Resending a batch is therefore safe, and it is the way to correct a state you already sent.
Latest Timestamp (Sync Checkpoint)
Section titled “Latest Timestamp (Sync Checkpoint)”GET /api/external-excavator-state/latest-timestamp/{companyId}/{projectId}| Parameter | Description |
|---|---|
companyId | Your Ditio company id, the same value you send in companyId on import |
projectId | Your externalProjectId |
Response: 200 OK with a bare JSON number: the timeStamp of the newest
record for that company and external project, in Unix seconds (UTC). It is 0
when there are no records.
1790926872How to use it is described under Sync checkpoint.
Aggregated Data Per State
Section titled “Aggregated Data Per State”POST /api/external-excavator-state/aggregated-data-per-stateAggregates the records of one external project in a period, for your company.
Request body
Section titled “Request body”| Field | Type | Description |
|---|---|---|
dateFrom | string (date-time) | Start of the period (inclusive). |
dateTo | string (date-time) | End date. The whole day is included: send the date at midnight, e.g. 2026-10-02T00:00:00Z covers up to 2026-10-02T23:59:59Z. |
projectId | string | Your externalProjectId. Only records with exactly this value are counted, so always send it. |
excavatorIds | array of string | Optional. Matched against the record id (Ditio’s id), not externalMachineId. Leave it out or send [] to include every machine. |
{ "dateFrom": "2026-10-01T00:00:00Z", "dateTo": "2026-10-02T00:00:00Z", "projectId": "SITE-17", "excavatorIds": []}Response
Section titled “Response”200 OK with an object keyed by the state number as a string. All three
keys are always present.
{ "0": 41, "1": 12, "2": 87}Get State by Id
Section titled “Get State by Id”GET /api/external-excavator-state/{id}Response: 200 OK with the state record. An id that
is not a 24-character hex string gives 400 (InvalidExternalExcavatorState);
an unknown id gives 404.
Update
Section titled “Update”PUT /api/external-excavator-state/{id}Delete
Section titled “Delete”DELETE /api/external-excavator-state/{id}Response: 200 OK with the deleted record. An id that is not a
24-character hex string gives 400; an unknown id gives 404
(ExternalExcavatorStateNotFound).
Errors
Section titled “Errors”Error bodies, status codes and retry rules are described in Error Handling. Specific to this API:
| Status | When |
|---|---|
400 | The body is not valid JSON, a field can’t be read as its type (for example state as a string), geoPoint.type is missing or not "Point"/"Polygon", the import array is empty, or an {id} is not a 24-character hex string |
401 | The token is missing, expired or lacks the masstransportapiv1 scope |
404 | No record with that {id} (get and delete) |
Related
Section titled “Related”- Machine Integration guide: step-by-step walkthrough
- Machine Data: sync the machine catalogue and extract machine usage
- External Weight Measures: weighbridge data