Skip to content

Export Time Data

This guide shows you how to pull time registration data from Ditio into your own systems. Common use cases include feeding a BI dashboard, syncing with a payroll provider, or archiving records in a data warehouse.

  • You want to export hours logged by field workers for payroll processing
  • You’re building a BI dashboard that shows labor hours across projects
  • You need to sync Ditio time data with an ERP system (SAP, Visma, etc.)
  • You want to archive approved time registrations in your own database
  • API credentials with the reportingapiv1 scope — see Authentication
  • Understanding of Pagination (responses are paginated)
Terminal window
# Test (default for all examples)
export DITIO_IDENTITY_BASE="https://identity.ditio.dev"
export DITIO_REPORTING_BASE="https://core-api.ditio.dev/reporting"

Ditio stores time registrations when field workers log their hours via the mobile app. These records go through an approval workflow (field entry → foreman approval → payroll). The Data Extraction API lets you pull these records with a paginated, incremental-sync-friendly contract.

Terminal window
TOKEN=$(curl -s -X POST "$DITIO_IDENTITY_BASE/connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "scope=reportingapiv1" | jq -r '.access_token')

Query for a date range:

Terminal window
curl -H "Authorization: Bearer $TOKEN" \
"$DITIO_REPORTING_BASE/v1/time-registrations?FromDateTime=2026-01-01&ToDateTime=2026-01-31"

Follow continuationToken until all records are retrieved. See Pagination.

Each record includes the worker, project, work order, date and hours, and approval state — plus the IDs you can resolve against the metadata endpoints (users, projects, resources).

import os
import requests
IDENTITY_BASE = os.environ.get("DITIO_IDENTITY_BASE", "https://identity.ditio.dev")
REPORTING_BASE = os.environ.get("DITIO_REPORTING_BASE", "https://core-api.ditio.dev/reporting")
# Authenticate
auth = requests.post(f"{IDENTITY_BASE}/connect/token", data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "reportingapiv1",
})
token = auth.json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
# Fetch all time registrations for January 2026
records = []
params = {"FromDateTime": "2026-01-01", "ToDateTime": "2026-01-31"}
while True:
page = requests.get(
f"{REPORTING_BASE}/v1/time-registrations",
headers=headers, params=params,
).json()
records.extend(page["data"])
continuation = page.get("continuationToken")
if not continuation:
break
params["ContinuationToken"] = continuation
print(f"Exported {len(records)} time registrations")
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
var reportingBase = Environment.GetEnvironmentVariable("DITIO_REPORTING_BASE")
?? "https://core-api.ditio.dev/reporting";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
var allRecords = new List<JsonElement>();
var baseQuery = $"{reportingBase}/v1/time-registrations" +
"?FromDateTime=2026-01-01&ToDateTime=2026-01-31";
var url = baseQuery;
while (url is not null)
{
var page = await http.GetFromJsonAsync<JsonElement>(url);
allRecords.AddRange(page.GetProperty("data").EnumerateArray());
url = page.TryGetProperty("continuationToken", out var token)
&& token.ValueKind == JsonValueKind.String
? $"{baseQuery}&ContinuationToken={Uri.EscapeDataString(token.GetString()!)}"
: null;
}

For recurring exports, pass ModifiedSince = <last successful sync timestamp> instead of a work-date window. Incremental mode returns records created and edited since that instant, so late corrections are picked up without re-processing the entire history. See Pagination.

IssueCauseFix
403 ForbiddenToken missing the reportingapiv1 scopeRequest the scope explicitly when fetching the token
Edits missing from exportsFull sync only sees the date windowUse ModifiedSince incremental sync for recurring pulls
Slow unbounded pullsNo window on a large tenantChunk backfills month-by-month; keep ModifiedSince tight