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.
Concepts
Section titled “Concepts”| Term | What it is |
|---|---|
| Project | A 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. |
| Document | Any 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. |
| Section | Optional 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.id | The id Ditio returns when you push a document. Save it — you need it to download or delete that document later. |
pageExternalId | Returned 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.
Step 1 — Get a token
Section titled “Step 1 — Get a token”Set your environment once (defaults to test):
# 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"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')Step 2 — Find your project’s id
Section titled “Step 2 — Find your project’s id”curl "$DITIO_API_BASE/api/v4/integration/projects" \ -H "Authorization: Bearer $TOKEN"Or, if you already know the project number:
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.
Step 3 — Find work orders in a project
Section titled “Step 3 — Find work orders in a project”curl "$DITIO_API_BASE/api/v4/integration/tasks/project/65f1a2b3c4d5e6f7a8b9c0d1" \ -H "Authorization: Bearer $TOKEN"More work-order endpoints: Work Orders.
Step 4 — Upload documents
Section titled “Step 4 — Upload documents”To a project
Section titled “To a project”POST /api/v4/integration/projects/{id}/documentsSend one or more files as multipart/form-data. Query parameters (both
optional):
| Param | Effect |
|---|---|
section | Groups 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. |
replaceExistingFilesWithSameName | When true, documents already on the page with the same filename are replaced (use on re-sync to avoid duplicates). |
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.
To a work order
Section titled “To a work order”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.
curl -X POST "$DITIO_API_BASE/api/v4/integration/tasks/66a1b2c3d4e5f6a7b8c9d0e2/documents" \ -H "Authorization: Bearer $TOKEN" \ -F "file=@/path/to/Method-statement.pdf"Where documents land
Section titled “Where documents land”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.pdfEach 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}/documentsGET /api/v4/integration/tasks/{id}/documentsReturns 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:
curl "$DITIO_API_BASE/api/v4/integration/projects/{id}/documents/{fileReferenceId}" \ -H "Authorization: Bearer $TOKEN" -o Drawing-A1.pdfA 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.
C# example — upload with a cached token
Section titled “C# example — upload with a cached token”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();Limitations & notes
Section titled “Limitations & notes”- Auth & scope: Administrator-level API client,
ditioapiv3scope.401= token missing/expired; a403/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;replaceExistingFilesWithSameNamematches by filename. - Any file type is accepted (PDF, Word, images, …).
- Dates are ISO 8601; IDs are strings.
Postman
Section titled “Postman”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).
Related
Section titled “Related”- Projects · Work Orders — finding the ids you upload to
- PDF Extraction — pulling the PDFs Ditio generates (the reverse direction)
- Authentication — token flow and caching