Safety Reporting
HSE data is only useful if it reaches the people who act on it. Ditio captures incidents (alerts), checklist submissions, and machine inspections in the field — this guide covers pulling that data out for HSE dashboards, compliance archives, and external safety management systems.
When to use this
Section titled “When to use this”- You aggregate HSE KPIs (incident counts, checklist completion rates) across systems in a BI tool
- Your compliance process requires archiving submitted checklists and incident reports as PDFs outside Ditio
- You forward incidents to an external safety management system
Prerequisites
Section titled “Prerequisites”- API credentials with the
reportingapiv1scope — see Authentication - Understanding of Pagination — all extraction endpoints use continuation tokens
# Test (default for all examples)export DITIO_REPORTING_BASE="https://core-api.ditio.dev/reporting"
# Production — only after verifying in test# export DITIO_REPORTING_BASE="https://core-api.ditio.app/reporting"Available endpoints
Section titled “Available endpoints”| Endpoint | Description |
|---|---|
GET /v1/incident-registrations | Safety/HSE incident reports (alerts) |
GET /v1/checklist-registrations | QA and safety checklist submissions |
GET /v1/machine-checklist-registrations | Machine inspection checklists |
GET /v1/machine-incident-registrations | Machine-specific safety incidents |
All four support the shared extraction filters (FromDateTime/ToDateTime
for full sync, ModifiedSince/ModifiedBefore for incremental sync,
ProjectId, CompanyId, ChunkLimit, ContinuationToken).
Step 1 — Pull incident registrations
Section titled “Step 1 — Pull incident registrations”curl -s -G "$DITIO_REPORTING_BASE/v1/incident-registrations" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "FromDateTime=2026-06-01T00:00:00Z" \ --data-urlencode "ToDateTime=2026-07-01T00:00:00Z"Follow continuationToken until empty. For ongoing syncs, switch to
ModifiedSince with your last successful sync timestamp — that also catches
records edited after the fact.
Step 2 — Archive the generated PDFs
Section titled “Step 2 — Archive the generated PDFs”Each incident, checklist, and absence record carries a pdfUrl field — an
absolute link to the PDF Ditio generated when the record was submitted. It is
null until generation has happened; skip those records and pick them up on
the next sync. Fetch the bytes with the same bearer token. Full details:
PDF Extraction.
curl -s -G "$DITIO_REPORTING_BASE/v1/checklist-registrations" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "ModifiedSince=2026-06-01T00:00:00Z" \| jq -r '.data[] | select(.pdfUrl != null) | .pdfUrl' \| while read -r url; do curl -sL -H "Authorization: Bearer $TOKEN" -O "$url"; doneChecklist records also expose the files attached inside the checklist via
sections[].attachments[].url and sections[].images[].url.
Step 3 — Pull the site photos
Section titled “Step 3 — Pull the site photos”Photos attached to incidents and checklists (and feed posts) are available in
one paginated stream through
Image Extraction, with
GPS coordinates, uploader, and project/task context per image. Use
Sources=alert,checklist to skip feed images:
curl -s -G "$DITIO_REPORTING_BASE/v1/images" \ -H "Authorization: Bearer $TOKEN" \ --data-urlencode "Sources=alert" \ --data-urlencode "Sources=checklist" \ --data-urlencode "ModifiedSince=2026-06-01T00:00:00Z"Python example — incremental HSE sync
Section titled “Python example — incremental HSE sync”import osimport requests
REPORTING_BASE = os.environ.get( "DITIO_REPORTING_BASE", "https://core-api.ditio.dev/reporting")headers = {"Authorization": f"Bearer {token}"}
def extract_all(endpoint, last_sync_timestamp): params = {"ModifiedSince": last_sync_timestamp} while True: page = requests.get( f"{REPORTING_BASE}/v1/{endpoint}", headers=headers, params=params ).json() yield from page["data"] continuation = page.get("continuationToken") if not continuation: break params["ContinuationToken"] = continuation
last_sync = "2026-06-01T00:00:00Z"for incident in extract_all("incident-registrations", last_sync): forward_to_hse_system(incident) # your logic if incident.get("pdfUrl"): pdf = requests.get(incident["pdfUrl"], headers=headers).content archive_pdf(incident["id"], pdf) # your logicCommon issues
Section titled “Common issues”| Issue | Cause | Fix |
|---|---|---|
pdfUrl is null | The PDF hasn’t been generated yet (happens on submit/report) | Skip and pick up on the next incremental sync |
| Missing recent edits | Full sync filters on creation window | Use ModifiedSince incremental sync for ongoing pulls |
403 Forbidden | Token lacks access to the requested project/company | Check the ProjectId/CompanyId filter and your client’s company |
Related
Section titled “Related”- PDF Extraction — the
pdfUrlmechanics in detail - Image Extraction — site photos with GPS and context
- Project Data — resolving project IDs in incident records