Files and uploads

Put files into a space with a presigned upload. Then poll until parsing finishes.
View as Markdown

Upload a file into a space with a two-step, presigned flow. First register the file to get a short-lived upload URL. Then PUT the bytes directly to storage. Registration requires space:contribute on the space. Reading requires space:read.

Uploads never stream through the gateway. You always PUT to a presigned upload URL from your own environment. Use this path for large files. Also use it for any file you want to keep in a space, unlike the transient /process API.

The flow

1

Register the file

POST /spaces/{spaceId}/files returns a presigned upload URL.

2

Upload the bytes

PUT the raw file to that URL. The Content-Type must exactly match the mimeType you registered.

3

Poll until terminal

GET /spaces/{spaceId}/files/{fileId} until status settles. Then read the download URLs.

1. Register

POST
/spaces/:spaceId/files
1curl -X POST https://api.cloudraker.com/spaces/spaceId/files \
2 -H "Authorization: Bearer <token>" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "fileName": "invoice.pdf",
6 "mimeType": "application/pdf"
7}'

Body fields:

  • fileName (required)
  • mimeType (required) — sets the stored record and the exact Content-Type the PUT must send.
  • size — bytes, optional.
  • processingKind — optional. Accepts the same five values as /process (doc-simple, doc-ocr, doc-auto, audio-transcribe, audio-transcribe-and-diarize).
  • indexVectors / indexOntology — optional booleans, both default true. The file is indexed for search and the knowledge graph unless you opt out.

The API ignores any parentType/parentId in the body. The parent is forced to :spaceId.

Response — 201

1{
2 "id": "",
3 "uploadUrl": "https://…storage…/…",
4 "uploadExpiresAt": "2026-07-20T12:15:00.000Z",
5 "file": { }
6}

uploadUrl is a presigned upload URL valid for 15 minutes (uploadExpiresAt).

2. Upload the bytes

PUT the raw file directly to uploadUrl. The bytes go directly to object storage, not through the gateway. The Content-Type must be exactly the mimeType you registered. A mismatch rejects the PUT.

$curl -X PUT "<uploadUrl>" \
> -H "Content-Type: application/pdf" \
> --data-binary @./invoice.pdf

3. Poll until terminal

GET
/spaces/:spaceId/files/:fileId
1curl https://api.cloudraker.com/spaces/spaceId/files/fileId \
2 -H "Authorization: Bearer <token>"

Poll status until it settles:

StatusMeaning
waiting / processingKeep polling
storedUploaded. No processing was requested.
processedProcessing succeeded
failedSee processingError

Once the status is terminal, the record’s urls object carries minted download links. The links are valid for about 1 hour:

  • urls.file — the original file
  • urls.processedMd — extracted markdown (once produced)
  • urls.processedJson — structured / grounded JSON (once produced)

An audio-transcribe or audio-transcribe-and-diarize file produces no markdown. urls.processedMd stays absent, and urls.processedJson holds the transcript. On the public /v1 surface these two links are named urls.markdown and urls.json.

List files in a space

GET
/spaces/:spaceId/files
1curl https://api.cloudraker.com/spaces/spaceId/files \
2 -H "Authorization: Bearer <token>"

?limit defaults to 50, max 200. Files have no cursor. The list returns a single most-recent page. See Pagination and filtering.

Retry a failed file

POST
/spaces/:spaceId/files/:fileId/reprocess
1curl -X POST https://api.cloudraker.com/spaces/spaceId/files/fileId/reprocess \
2 -H "Authorization: Bearer <token>"

Resets the file to waiting. Returns 409 if the file is not currently failed.

Access to a file id from the wrong space returns 404. Existence is hidden across spaces as a space:read leak-guard. Org admins bypass space checks.

Org-level template files

Organization template files use the same presigned shape under POST /organization/templates.

Where to go next