# Files and outputs

> Reserve and complete uploads, follow signed storage instructions, use stable file IDs in runs, and distinguish temporary download URLs from retained files.

Source: https://kaitoi.io/docs/core/files-and-outputs/
Section: Kaitoi Core / REST API
Written for: Developers uploading inputs and retaining API output files.
Last reviewed: 2026-10-24

---

A file reservation, uploaded bytes, a completed file, and a download URL are
different stages. Follow the returned upload instructions rather than treating
a local path or signed URL as a permanent Kaitoi file identifier.

All routes here are relative to `/api/v1`.

## Separate a file from its upload request


Reserve an upload with POST /files/uploads, then transfer every required part using its returned storage method, URL and headers. Keep the REST bearer at the API boundary. Complete the upload through POST /files/uploads/{id}/complete and use the successful fileId in the receiving schema. Reservation alone uploads no bytes. If a download URL expires, request a fresh authorized URL; the file's retention lifetime is separate.

The authored plant.png file is transferred as illustrative byte ranges with their ETags, not as cropped images, then associated with completed file ID f1. A temporary download-URL ticket expires independently of that retained file identity.

*Figure: Keep the returned file reference and follow the consuming schema.*

## Reserve an upload

With `files:write`, call `POST /files/uploads` with `filename`, `sizeBytes`,
and optional `contentType`, `sha256`, and supported external identifiers.
Use a stable `Idempotency-Key` for a supported logical reservation retry.
The response reserves storage; it has not uploaded your bytes.

## Transfer bytes using the returned instructions

Follow `storageMethod`, the returned `upload.method`, `url`, and `headers`.
Single-part and proxied-relay uploads use their documented transfer contract.
Multipart uploads require each returned part and its ETag. Keep the part
numbers and ETags for completion.

Do not send your REST Authorization bearer to a signed storage URL. Use only
the returned storage headers. A local filesystem path must be uploaded; it
is not an API file reference.

## Complete before referencing the file

Call `POST /files/uploads/{upload_id}/complete`. Supply the applicable
`actualSizeBytes`, `actualSha256`, and `multipartParts` contract. Multipart
completion needs its part-number/ETag list; a multipart reservation with a
hash needs the actual hash on completion. Completion is idempotent by upload
ID. Use the resulting `fileId` only after success.

Abort a pending reservation through `DELETE /files/uploads/{upload_id}` when
appropriate. The older multipart `POST /files` convenience route is limited
to 25 MB; the upload-session flow is the primary integration contract.

## Keep identifiers and credentials separate

**Reserve:** create the upload session; no bytes have been sent yet.
**Transfer:** follow returned method/URL/headers, retaining multipart ETags;
never attach the REST bearer to signed storage URLs. **Complete:** finalize
the upload and use its fileId. Download URLs expire independently of the file
record, and deletion can be refused while active references remain.

## Inspect, download, and retain outputs

Use `GET /files/{file_id}` or `/download-url` with `files:read`. A returned
download URL is temporary; keep the `fileId` and request a fresh URL when
needed. `expiresInSeconds` is 60–86400, default 3600, for that download request.
Run file outputs can also include filename, content type, size and preview
URLs with separate expiry facts.

REST `fileId`, Library ID, storage filename, and OS path are different values.
For inline run inputs or overrides, use the transport shape
`{"type":"file","fileId":"<completed file ID>"}`. Do not substitute a
temporary download URL for a stable file reference.

Deletion uses `files:write` and can refuse a file still referenced by active
projects, or when reference safety is unknown. Resolve those references
deliberately. See [Runs, progress and cancellation](/docs/core/runs-and-files/)
for results and [Errors and retries](/docs/core/errors-and-retries/) for recovery.
