Skip to main content

Document uploads

Audience

Integrators uploading evidence documents to a project.

What you'll accomplish

Upload a file via the presigned flow, finalize the source, and know where to poll for extraction status.

Project documents are sources (kind: document). Uploading triggers background extraction. The complete response includes sourcePid for polling.

Requires projects:write. See Authentication.

Presigned upload

File bytes go directly to object storage. This is the supported path for integrators and large files.

POST /projects/:projectPid/documents/upload-init
→ uploadUrl + storage key
PUT uploadUrl (no Authorization header)
POST /projects/:projectPid/documents/upload-complete
→ sourcePid

Step-by-step

1. Init — presigned PUT URL (valid five minutes):

curl -sS -X POST 'https://api.air.thalus.ai/projects/<projectPid>/documents/upload-init' \
-H 'Authorization: Bearer <rawKey>' \
-H 'Content-Type: application/json' \
-d '{"filename":"evidence.pdf","contentType":"application/pdf"}'

2. UploadPUT raw file to uploadUrl with the same Content-Type. No AIR auth header.

3. Complete — start extraction:

curl -sS -X POST 'https://api.air.thalus.ai/projects/<projectPid>/documents/upload-complete' \
-H 'Authorization: Bearer <rawKey>' \
-H 'Content-Type: application/json' \
-d '{
"s3Key": "<storage key from init>",
"filename": "evidence.pdf",
"contentType": "application/pdf"
}'

Poll GET /projects/:projectPid/documents until status is no longer processingAsync jobs.

Limits and supported types

LimitValue
Max file size50 MiB per file
Max artifacts per assessment5
Presigned URL TTL5 minutes

Supported extensions: .pdf, .docx, .pptx, .xlsx, .txt, .md, .csv.

Very large files may time out during extraction even when upload succeeds.

Common failures

SymptomLikely causeFix
403 on initMissing projects:writeAdd scope or use integrations:full
404 on initWrong projectPid or wrong domainGET /domains/&lt;domainPid&gt;/projects
PUT fails or 403 from storageWrong Content-Type, expired URL, or corrupt bodyRe-run init within five minutes; match Content-Type
409 on completeStorage key already used or upload never finishedFresh init → PUT → complete
Source error after completeUnsupported or corrupt fileCheck lastError on document row
Stuck in processingLarge file or parser timeoutWait with backoff; check lastError; retry regenerate if needed

After upload

ActionRoute
List documentsGET /projects/:projectPid/documents
List artifactsGET /projects/:projectPid/artifacts
Download originalGET /projects/:projectPid/documents/:sourcePid/download
Re-run extractionPOST /projects/:projectPid/documents/:sourcePid/regenerate
ArchivePOST /projects/:projectPid/documents/:sourcePid/archive

Deleting a document archives derived artifacts used as assessment evidence.