Crew List (Mannskapsliste)
This guide shows you how to pull the crew list (Norwegian: mannskapsliste) from Ditio: who checked in on your projects and when they left, with project, employer, HSE card and check-in details. This is the data behind the crew list screen and Excel export in Ditio Web.
When to use this
Section titled “When to use this”- You need attendance records per construction site (e.g. for byggherreforskriften mannskapsliste requirements or client audits)
- You want to sync who is on site into an HSE, access-control or BI system
- You need to know who is on site right now
Prerequisites
Section titled “Prerequisites”- API credentials with the
reportingapiv1scope — see Authentication - Results are scoped to the company and projects your credentials can access
Examples use the environment variables from Environments and default to the test environment.
How it works
Section titled “How it works”Field workers check in and out via the Ditio mobile app, the browser, or an on-site Ditio terminal (card reader). Each check-in creates a passage tied to a project. The crew list endpoint returns those passages — including workers from subcontractor companies on your projects, and terminal card swipes from people who are not Ditio users.
You get one record per passage, not one per person per day. If someone
leaves site and comes back, that is two records. A passage that is still
open — the person has not checked out — comes back with
checkOutDateTime: null and isOnSite: true.
Step-by-step
Section titled “Step-by-step”1. Authenticate
Section titled “1. Authenticate”Get a token with scope=reportingapiv1 into $TOKEN (set DITIO_SCOPE=reportingapiv1), as shown in
Getting a token in your scripts.
2. Fetch the crew list
Section titled “2. Fetch the crew list”curl -s "$DITIO_REPORTING_BASE/v1/crew-list-registrations" \ -H "Authorization: Bearer $TOKEN"With no date parameters you get today, which is what you want for “who is on site now”. “Today” is the current UTC day (00:00–24:00 UTC), not your local day: in Norway, a check-in just after local midnight belongs to the previous UTC day until 01:00 or 02:00 local time.
Query parameters:
| Parameter | Description |
|---|---|
ProjectIds | Comma-separated project ids. Omit for all projects you can access |
ProjectId | A single project id. Can be combined with ProjectIds |
FromDateTime / ToDateTime | A historical date window. Supply both or neither |
ModifiedSince / ModifiedBefore | Incremental sync — see below |
IncludeOpen | Include passages with no check-out yet. Defaults to true |
Paging (ContinuationToken, ChunkLimit) works as on every extraction
endpoint — see Pagination.
3. Keep in sync
Section titled “3. Keep in sync”For an integration that runs continuously, sync on ModifiedSince rather
than re-reading a date window. Pass the time of your last successful sync;
you get everything created or changed since, including passages whose
check-in was days earlier.
curl -s "$DITIO_REPORTING_BASE/v1/crew-list-registrations?ModifiedSince=2026-08-17T09:00:00Z" \ -H "Authorization: Bearer $TOKEN"Records are paged; follow continuationToken until it is empty, as described
in Pagination.
Records removed in Ditio come back as tombstones with isDeleted: true, so
you can retract them on your side. See
How extraction works for the full
sync model.
4. Read the response
Section titled “4. Read the response”{ "data": [ { "id": "5f2b8c1de4b0a12f34d56a78", "checkInSource": "App", "userId": "7f3a09e2-1b64-4c1d-9a0e-2f5d8c4b7a11", "name": "Ola Nordmann", "firstName": "Ola", "lastName": "Nordmann", "birthDate": "01.05.1986", "hseCardId": "4388261", "hseCardExpirationDate": "2027-02-11T00:00:00Z", "organizationNumber": "987654321", "companyName": "Entreprenør AS", "isDitioUser": true, "projectId": "5f2b8c1de4b0a12f34d56a78", "projectName": "Example Road – Phase 2", "projectNumber": "1042", "externalHmsRegId": "1234567", "checkInDateTime": "2026-08-17T06:58:12Z", "checkOutDateTime": null, "isOnSite": true, "autoCompleted": false, "createdDateTime": "2026-08-17T06:58:12Z", "modifiedDateTime": "2026-08-17T06:58:12Z", "isDeleted": false } ], "continuationToken": null, "syncTypeName": "full", "recordCount": 1, "deletedRecordCount": 0}Field notes:
| Field | Description |
|---|---|
checkInDateTime / checkOutDateTime | When the person arrived and left, in UTC. checkOutDateTime is null while they are still on site |
isOnSite | true while the passage is open. This is the “who is here now” flag |
hseCardId / hseCardExpirationDate | HSE card (byggekort) number and expiry, when registered. null if the worker has no card on file |
organizationNumber / companyName | The employer of the checked-in worker — subcontractors report their own company |
isDitioUser | false for terminal card swipes by people without a Ditio account |
checkInSource | Where the check-in was registered, e.g. App, Browser, Terminal or Integration. Treat it as an open set: other values can appear, so don’t fail on one you don’t recognise |
autoCompleted | true if the check-out was performed automatically rather than by the worker |
externalHmsRegId | The project’s HMSREG number, when configured |
isDeleted | Tombstone — the passage was removed in Ditio |
Python
Section titled “Python”import os# 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')}"}last_sync = "2026-08-17T09:00:00Z" # the time of your last successful syncparams = {"ModifiedSince": last_sync, "IncludeOpen": "true"}
for record in fetch_all(f"{REPORTING_BASE}/v1/crew-list-registrations", headers, params): if record["isDeleted"]: retract(record["id"]) # your logic elif record["isOnSite"]: mark_on_site(record) # your logic else: mark_left(record) # your logicusing System.Net.Http.Headers;
var reportingBase = Environment.GetEnvironmentVariable("DITIO_REPORTING_BASE") ?? "https://core-api.ditio.dev/reporting";var lastSync = "2026-08-17T09:00:00Z"; // the time of your last successful sync
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/crew-list-registrations" + $"?ModifiedSince={Uri.EscapeDataString(lastSync)}&IncludeOpen=true";
// DitioPaging.FetchAllAsync: see /getting-started/pagination/#fetching-all-pages-in-codeawait foreach (var record in DitioPaging.FetchAllAsync<CrewListRecord>(http, url)){ if (record.IsDeleted) Console.WriteLine($"Retract {record.Id}"); else if (record.IsOnSite) Console.WriteLine($"{record.Name} is on site at {record.ProjectName}"); else Console.WriteLine($"{record.Name} left {record.ProjectName} at {record.CheckOutDateTime:u}");}
// Only the fields this example reads; add the others from the response as you need them.record CrewListRecord( string Id, string? Name, string? ProjectName, DateTime CheckInDateTime, DateTime? CheckOutDateTime, bool IsOnSite, bool IsDeleted);A complete, runnable integration — polling this endpoint and pushing
passages to an external HSE register — is in the
integration samples repository
under crew-list-chkbox/.
The “Ditio Mannskapsliste” Excel file is a download in Ditio Web and is not part of the supported API. To produce a similar file from your integration, build it from the records above.