Files API guide
Files (called resources in some schemas) hold the evidence attached to Threads: images, PDFs, documents, and scan artifacts. A file can be attached to a Thread directly or as the value of a resource-typed field.
There are two upload paths: a simple one-shot POST for small files, and the resumable tus protocol for large ones. Full schemas: API reference.
Endpoints at a glance
Section titled “Endpoints at a glance”| Operation | Method & path |
|---|---|
| Simple upload | POST /api/v1/files |
| Resumable upload (tus) | POST /api/v1/files/upload, then PATCH /api/v1/files/upload/{id} |
| Finalize tus uploads | POST /api/v1/files/finalize |
| Download | GET /api/v1/files/{resource_id}/download |
| Signed URLs | POST /api/v1/files/urls |
| Search files | GET /api/v1/files/search |
| List files (cursor) | GET /api/v1/files |
| List a Thread’s files | GET /api/v1/threads/{thread_id}/files |
Simple upload
Section titled “Simple upload”For files a single request can carry comfortably, POST multipart/form-data with the file and optional attachment targets. The response includes the created resource with a signed URL:
curl -fsS "$APID_URL/api/v1/files" \ -H "Authorization: Bearer $DUST_TOKEN" \ -H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \ -F "file=@inspection-report.pdf" \ -F "threadId=$THREAD_ID"const resources = await client.files.upload({ file, // a File threadId, // optional: attach to a Thread // fieldId, // optional: attach as a field value // isPrivate: true, // optional});fieldId attaches the file as the value of a resource-typed field; isPrivate restricts visibility.
Resumable upload (tus)
Section titled “Resumable upload (tus)”Large files use the tus 1.0 resumable-upload protocol at /api/v1/files/upload, then a finalize call that turns the completed upload into a resource record. The flow is upload → finalize → (already attached, or attach via fields).
-
Create the upload. POST with tus headers;
Upload-Metadatavalues are base64-encoded, andfilenameis required (optionalfieldId,threadId):Terminal window curl -i -X POST "$APID_URL/api/v1/files/upload" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \-H "Tus-Resumable: 1.0.0" \-H "Upload-Length: 52428800" \-H "Upload-Metadata: filename $(printf 'video.mp4' | base64)"# → 201 Created# → Location: …/api/v1/files/upload/<upload-id>The
<upload-id>in the returnedLocationis the upload’s resource ID — keep it. -
Send the bytes (resumable — repeat PATCHes continue from
Upload-Offset):Terminal window curl -i -X PATCH "$APID_URL/api/v1/files/upload/$UPLOAD_ID" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \-H "Tus-Resumable: 1.0.0" \-H "Upload-Offset: 0" \-H "Content-Type: application/offset+octet-stream" \--data-binary @video.mp4To resume after an interruption,
HEADthe same URL to read the currentUpload-Offset, then PATCH from there. Any tus 1.0 client library (e.g.tus-js-client) speaks this protocol for you. -
Finalize. Uploads become resource records only after finalize:
Terminal window curl -fsS "$APID_URL/api/v1/files/finalize" \-H "Authorization: Bearer $DUST_TOKEN" \-H "Dust-Ctx-Org-Id: $DUST_ORG_ID" \-H "Content-Type: application/json" \-d '{"threadId": "'"$THREAD_ID"'","requests": [{ "resId": "'"$UPLOAD_ID"'", "filename": "video.mp4", "size": 52428800 }]}'POST /api/v1/files/finalizeaccepts many uploads at once; each request item takes the tus upload ID asresIdplusfilenameandsize(optionalfieldId,isPrivate). The response returns the created resources with signed URLs.
Downloads and signed URLs
Section titled “Downloads and signed URLs”GET /api/v1/files/{resource_id}/download— stream the file through the API.POST /api/v1/files/urls?ids=<id>&ids=<id>— mint short-lived signed URLs for direct object-storage access; use these when a browser or downstream system needs the bytes without proxying.
Search and listing
Section titled “Search and listing”Two query styles exist:
GET /api/v1/files/search— page-indexed search withq,threadId,mimeFilters, andincludeArchived.GET /api/v1/files— cursor-paginated listing (cursor,pageSize;includeArchivedis required) filtered bythreadIdorcreatedBy.
For files in the context of one Thread, prefer GET /api/v1/threads/{thread_id}/files (see the Threads guide).
Related pages
Section titled “Related pages”- Threads API guide — attaching files to Thread fields and thumbnails
- Core model — where files sit in the domain
- API reference — full parameter and schema detail
