Skip to content

Documents

Push documents (PDF, Word, images, …) to Ditio projects and work orders. Documents you push surface in the Ditio Info Center, so field workers assigned to the project see them in the mobile app — grouped into a folder per project, and (optionally) into named sections within it. Typical use: a document management system that keeps drawings, contracts, and method statements in sync with the crews on site.

Scope: ditioapiv3 · Your API client must have Administrator access, and can only see and act on projects in your own company.

TermWhat it is
ProjectA top-level job in Ditio. Has a Ditio id (a string like 65f1a2b3c4d5e6f7a8b9c0d1) and a human project number (e.g. P-2026-001).
Work order (a task in the API)A unit of work inside a project. Also has a Ditio id.
DocumentAny file you push to a project or work order. It becomes a document on an Info Center page, visible to that project’s members on mobile.
SectionOptional name that groups a project’s documents into a page (e.g. Drawings, Contracts). Re-using the same (project, section) adds to the same page. Omit it and documents land on a default “Documents” page.
fileReference.idThe id Ditio returns when you push a document. Save it — you need it to download or delete that document later.
pageExternalIdReturned on upload; the stable handle of the Info Center page the documents landed on.

You push a document using the Ditio id of a project or work order — steps 2 and 3 below show how to find those ids.

Set your environment once (defaults to test):

Terminal window
# Test (default for all examples)
export DITIO_IDENTITY_BASE="https://identity.ditio.dev"
export DITIO_API_BASE="https://core-api.ditio.dev/core"
# Production — only after verifying in test
# export DITIO_IDENTITY_BASE="https://identity.ditio.app"
# export DITIO_API_BASE="https://core-api.ditio.app/core"
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=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=ditioapiv3" | jq -r '.access_token')
Terminal window
curl "$DITIO_API_BASE/api/v4/integration/projects" \
-H "Authorization: Bearer $TOKEN"

Or, if you already know the project number:

Terminal window
curl "$DITIO_API_BASE/api/v4/integration/projects/by-project-number/P-2026-001" \
-H "Authorization: Bearer $TOKEN"

The id in the response is what you attach documents to. More lookup endpoints: Projects.

Terminal window
curl "$DITIO_API_BASE/api/v4/integration/tasks/project/65f1a2b3c4d5e6f7a8b9c0d1" \
-H "Authorization: Bearer $TOKEN"

More work-order endpoints: Work Orders.

POST /api/v4/integration/projects/{id}/documents

Send one or more files as multipart/form-data. Query parameters (both optional):

ParamEffect
sectionGroups the documents onto a named page under the project’s document folder (e.g. Drawings). Re-use the same value to add more documents to that page. Omit it → a default “Documents” page.
replaceExistingFilesWithSameNameWhen true, documents already on the page with the same filename are replaced (use on re-sync to avoid duplicates).
Terminal window
curl -X POST "$DITIO_API_BASE/api/v4/integration/projects/65f1a2b3c4d5e6f7a8b9c0d1/documents?section=Drawings&replaceExistingFilesWithSameName=true" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@/path/to/Drawing-A1.pdf" \
-F "file=@/path/to/Site-plan.docx"

Response:

{
"successful": true,
"message": "Documents uploaded and attached ok",
"section": "Drawings",
"pageExternalId": "int-projdocs:65f1a2b3c4d5e6f7a8b9c0d1:drawings",
"files": [
{
"name": "Drawing-A1.pdf",
"size": 482113,
"url": "/api/file/66b1a2c3d4e5f6a7b8c9d0e2",
"fileReference": {
"id": "66b1a2c3d4e5f6a7b8c9d0e2",
"collectionRef": "InfoMessage",
"fileNameOrig": "Drawing-A1.pdf",
"fileType": "pdf",
"fileSize": 482113,
"createdDateTime": "2026-06-05T08:10:25Z"
}
}
],
"infoPageFiles": [
{ "fileReferenceId": "66b1a2c3d4e5f6a7b8c9d0e2", "name": "Drawing-A1.pdf" }
]
}

files are the documents created by this request; infoPageFiles is everything on the page after the upload. Store files[].fileReference.id — it’s the handle for downloading or deleting a document later.

Identical, using the work order id. The work order’s documents nest under its parent project’s folder; section defaults to the work order’s number/short description.

Terminal window
curl -X POST "$DITIO_API_BASE/api/v4/integration/tasks/66a1b2c3d4e5f6a7b8c9d0e2/documents" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@/path/to/Method-statement.pdf"

Behind the scenes, Ditio routes each document into the project’s Info Center — creating a folder per project and a page per section. The durable handle is (project, section); re-syncing to the same handle updates the same page rather than duplicating it:

📁 P-2026-001 – Prosjekt Fjellhall (folder, one per project)
├── 📑 Drawings (section page)
│ ├── 📎 Drawing-A1.pdf
│ └── 📎 Site-plan.docx
├── 📑 Contracts (section page)
│ └── 📎 Main-contract.pdf
└── 📑 Documents (default page — no section given)
└── 📎 Misc.pdf

Each project folder/page is scoped to that project, so it’s shown to active employees assigned to the project in your company.

Step 5 — List, download, replace, delete

Section titled “Step 5 — List, download, replace, delete”

List the document pages on a project or work order:

GET /api/v4/integration/projects/{id}/documents
GET /api/v4/integration/tasks/{id}/documents

Returns the section page(s) — each with section, pageExternalId, and a files array of { fileReferenceId, name }.

Download a document (use the fileReferenceId from upload/list):

GET /api/v4/integration/projects/{id}/documents/{fileReferenceId}
GET /api/v4/integration/tasks/{id}/documents/{fileReferenceId}

The endpoint streams the document bytes directly as the response body (200 OK, Content-Type: application/octet-stream, Content-Disposition carrying the original filename) — there is no JSON body:

Terminal window
curl "$DITIO_API_BASE/api/v4/integration/projects/{id}/documents/{fileReferenceId}" \
-H "Authorization: Bearer $TOKEN" -o Drawing-A1.pdf

A 404 means the document is not on that project/work order.

Replace — re-upload to the same (project, section) with ?replaceExistingFilesWithSameName=true (matches by filename).

Delete:

DELETE /api/v4/integration/projects/{id}/documents/{fileReferenceId}
DELETE /api/v4/integration/tasks/{id}/documents/{fileReferenceId}

Returns 204 No Content.

using System.Net.Http.Headers;
var apiBase = Environment.GetEnvironmentVariable("DITIO_API_BASE")
?? "https://core-api.ditio.dev/core";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
using var form = new MultipartFormDataContent();
var pdf = new ByteArrayContent(await File.ReadAllBytesAsync("Drawing-A1.pdf"));
pdf.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(pdf, "file", "Drawing-A1.pdf");
var projectId = "65f1a2b3c4d5e6f7a8b9c0d1";
var response = await http.PostAsync(
$"{apiBase}/api/v4/integration/projects/{projectId}/documents" +
"?section=Drawings&replaceExistingFilesWithSameName=true",
form);
response.EnsureSuccessStatusCode();
  • Auth & scope: Administrator-level API client, ditioapiv3 scope. 401 = token missing/expired; a 403/business error = the project or work order is not in your company.
  • Company-scoped: you only see and act on projects/work orders owned by your company (or its company structure).
  • Visibility: documents are shown to active employees assigned to the project, in the mobile app’s Info Center.
  • Grouping is by section. There is no separate version concept; replaceExistingFilesWithSameName matches by filename.
  • Any file type is accepted (PDF, Word, images, …).
  • Dates are ISO 8601; IDs are strings.

A ready-to-run Postman collection covering the integration endpoints — including these document endpoints, the token request, and project/work-order lookups — lives in the public samples repo: ditioas/Ditio.Core.Samples.Integrations (the postman/ folder: collection + Production/Test environment files).