Skip to content

Machine Integration

This guide covers how to send machine state data (excavator idle/working/moving states) from an external system into Ditio. This is the primary integration point for telematics providers and fleet management systems.

  • You have a fleet management system that tracks excavator operating states
  • You want machine utilization data to appear in Ditio’s production analytics
  • You need to sync historical machine data (daily batch uploads)
  • You’re a telematics provider integrating with Ditio on behalf of a customer
  • API credentials with the masstransportapiv1 scope — see Authentication
  • A company ID and project ID in Ditio, plus the Mass Transport API base URL (DITIO_MASSTRANSPORT_BASE in the examples below) — both provided by your Ditio contact during onboarding

Ditio tracks excavator states to calculate machine utilization and production rates. External systems can push state data via the Machine Integration API. Each state record represents a time period where a machine was in a specific operating state (idle, working, moving, etc.).

The typical flow:

  1. Your system collects machine state data from telematics hardware
  2. You push state records to Ditio (individually or in bulk)
  3. Ditio processes the data and makes it available in reports and dashboards
  4. Your customer sees combined Ditio + external machine data in one place
Terminal window
curl -X POST $DITIO_MASSTRANSPORT_BASE/api/external-excavator-state \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"companyId": "company-123",
"projectId": "project-456",
"machineId": "EX-001",
"state": "Working",
"startTime": "2025-01-15T08:00:00Z",
"endTime": "2025-01-15T08:45:00Z"
}'
Section titled “2. Bulk Import (Recommended for Production)”

For production integrations, use the bulk import endpoint to send multiple records at once:

Terminal window
curl -X POST $DITIO_MASSTRANSPORT_BASE/api/external-excavator-state/import \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '[
{
"companyId": "company-123",
"projectId": "project-456",
"machineId": "EX-001",
"state": "Working",
"startTime": "2025-01-15T08:00:00Z",
"endTime": "2025-01-15T08:45:00Z"
},
{
"companyId": "company-123",
"projectId": "project-456",
"machineId": "EX-001",
"state": "Idle",
"startTime": "2025-01-15T08:45:00Z",
"endTime": "2025-01-15T09:00:00Z"
}
]'

Before sending data, check what you’ve already sent by getting the latest timestamp:

Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"$DITIO_MASSTRANSPORT_BASE/api/external-excavator-state/latest-timestamp/company-123/project-456"

This returns the timestamp of the most recent record Ditio has received. Only send data newer than this to avoid duplicates.

Check machine utilization analytics:

Terminal window
curl -X POST $DITIO_MASSTRANSPORT_BASE/api/external-excavator-state/aggregated-data-per-state \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"companyId": "company-123",
"projectId": "project-456",
"fromDate": "2025-01-01",
"toDate": "2025-01-31"
}'
import requests
from datetime import datetime, timezone
import os
TOKEN = "your-access-token"
BASE_URL = os.environ["DITIO_MASSTRANSPORT_BASE"] + "/api/external-excavator-state"
HEADERS = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
COMPANY_ID = "company-123"
PROJECT_ID = "project-456"
# Step 1: Check sync checkpoint
latest = requests.get(
f"{BASE_URL}/latest-timestamp/{COMPANY_ID}/{PROJECT_ID}",
headers=HEADERS,
)
last_sync = latest.json().get("latestTimestamp")
print(f"Last synced: {last_sync}")
# Step 2: Collect new records from your system
new_records = [
{
"companyId": COMPANY_ID,
"projectId": PROJECT_ID,
"machineId": "CAT-336F",
"state": "Working",
"startTime": "2025-01-15T07:00:00Z",
"endTime": "2025-01-15T09:30:00Z",
},
{
"companyId": COMPANY_ID,
"projectId": PROJECT_ID,
"machineId": "CAT-336F",
"state": "Idle",
"startTime": "2025-01-15T09:30:00Z",
"endTime": "2025-01-15T10:00:00Z",
},
]
# Step 3: Bulk import
resp = requests.post(f"{BASE_URL}/import", headers=HEADERS, json=new_records)
if resp.status_code == 201:
print(f"Imported {len(new_records)} state records")
else:
print(f"Error: {resp.status_code} - {resp.text}")
ErrorCauseFix
400 ArgumentIsNullEmpty array sent to importInclude at least one record
401 UnauthorizedToken expiredRefresh your access token
403 ForbiddenToken missing the masstransportapiv1 scope, or client not enabled for the company/projectRequest the scope explicitly; contact your Ditio contact to enable write access