Machine Data
Machines are money on a construction site — knowing where each excavator is registered, how many hours it ran, and on whose project, is what makes fleet cost tracking work. This guide covers the two halves of machine data in Ditio: maintaining the machine catalogue (write) and extracting usage records (read).
When to use this
Section titled “When to use this”- Your fleet management system is the master record and Ditio should mirror it
- You bill customers for machine hours and need completed usage records — including when your machines work on other companies’ projects
- You’re building utilization dashboards per machine, project, or department
Prerequisites
Section titled “Prerequisites”- API credentials — see Authentication
- Scope
ditioapiv3for catalogue writes andreportingapiv1for usage extraction — see Which scope for which host
Examples use the environment variables from Environments and default to the test environment.
Part 1 — Sync the machine catalogue
Section titled “Part 1 — Sync the machine catalogue”Use the Machines API on
$DITIO_API_BASE to create and maintain machines. The short version:
- Fetch valid machine types —
GET /api/MachineTypereturns your company’s configured types; thetypeIdyou send on create must match one type’sTypeId - Create machines with your fleet numbers as
machineNumber - Keep them fresh —
PATCHhour meters and service dates on a schedule - Deactivate, don’t delete — retired machines get
active: false
The create request, full field reference, bulk endpoints, and how machines differ from equipment (attachments mounted on a machine) are in the Machines API reference.
Part 2 — Extract machine usage
Section titled “Part 2 — Extract machine usage”The Machine Registrations endpoint streams completed usage records for the machines your company owns — including registrations made on other companies’ projects (e.g. when your machine is rented out).
# Everything created or edited since your last synccurl -s -G "$DITIO_REPORTING_BASE/v1/machine-registrations" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "ModifiedSince=2026-07-01T00:00:00Z"Key behaviors:
- Incremental sync (
ModifiedSince) catches new and edited registrations — including edits to old records that a date-window query would miss. Deleted records arrive as tombstones withisDeleted: true. - Cross-company privacy: when your machine ran on another company’s
project, that company’s personal identifiers (
driverName,driverId) are returned asnull— you still get the machine, project, times, quantity, and the operator’s company name.
Python example — utilization per machine
Section titled “Python example — utilization per machine”import osfrom collections import defaultdict# Paste get_token (/getting-started/authentication/#getting-a-token-in-your-scripts) and fetch_all (/getting-started/pagination/#fetching-all-pages-in-code) above this.
REPORTING_BASE = os.environ.get( "DITIO_REPORTING_BASE", "https://core-api.ditio.dev/reporting")headers = {"Authorization": f"Bearer {get_token('reportingapiv1')}"}params = { "FromDateTime": "2026-06-01T00:00:00Z", "ToDateTime": "2026-07-01T00:00:00Z",}
hours_by_machine = defaultdict(float)for registration in fetch_all(f"{REPORTING_BASE}/v1/machine-registrations", headers, params): hours_by_machine[registration["machineName"]] += registration["qty"]
for machine_name, hours in sorted(hours_by_machine.items(), key=lambda x: -x[1]): print(f"{machine_name}: {hours:.1f}")C# example — utilization per machine
Section titled “C# example — utilization per machine”using System.Net.Http.Headers;
var reportingBase = Environment.GetEnvironmentVariable("DITIO_REPORTING_BASE") ?? "https://core-api.ditio.dev/reporting";
using var http = new HttpClient();// DitioAuth.GetTokenAsync: see /getting-started/authentication/#token-expiryhttp.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await DitioAuth.GetTokenAsync(http, "reportingapiv1"));
var url = $"{reportingBase}/v1/machine-registrations" + "?FromDateTime=2026-06-01T00:00:00Z&ToDateTime=2026-07-01T00:00:00Z";
var hoursByMachine = new Dictionary<string, double>();// DitioPaging.FetchAllAsync: see /getting-started/pagination/#fetching-all-pages-in-codeawait foreach (var registration in DitioPaging.FetchAllAsync<MachineRegistration>(http, url)){ var machineName = registration.MachineName ?? registration.MachineId ?? "(unknown)"; hoursByMachine[machineName] = hoursByMachine.GetValueOrDefault(machineName) + registration.Qty;}
foreach (var (machineName, hours) in hoursByMachine.OrderByDescending(entry => entry.Value)) Console.WriteLine($"{machineName}: {hours:F1}");
// Only the fields this example reads; driverName and driverId can be null.record MachineRegistration(string? MachineId, string? MachineName, double Qty);Machine catalogue export
Section titled “Machine catalogue export”To resolve machine IDs appearing in other exports (time registrations,
payroll lines) into names and numbers, use the resource metadata endpoint
(GET /v1/resource on the reporting base), which lists the machine
catalogue — see the Data Extraction reference.
Common issues
Section titled “Common issues”| Issue | Cause | Fix |
|---|---|---|
MachineService.machineTypeInvalid on create | typeId doesn’t match a configured type | Fetch GET /api/MachineType first and map your categories to valid TypeId values |
Machine type ids come back as TypeId, not typeId | GET /api/MachineType answers in PascalCase | Read TypeId, or send the header case: camel-case |
driverName / driverId are null in extraction | The registration involves another company’s employee | Expected — cross-company personal data is redacted by design |
| Edits missing from date-window pulls | Full sync only sees the stop-time window | Use incremental sync (ModifiedSince) for ongoing updates |
Related
Section titled “Related”- Machines API reference — full catalogue API reference
- Data Extraction reference — machine registrations and resource metadata
- Machine Integration — pushing machine telemetry into Ditio