Skip to main content
When a workflow input is a file, the SDK uploads it as multipart/form-data (the same shape as curl -F). No base64, no payload doubling. When the aggregate multipart payload (all file bytes plus form envelope headroom) would exceed ~4 MB, maintained client.run(...) helpers pre-upload enough files through the Files API (storage-direct on cloud, multipart fallback on-prem) with purpose: "run-input" and send {"$fileId": "file_..."} so cloud deployments stay under Vercel’s request-body limit. The server keeps those temporary pool files available for safe run-start retries and reaps them after 24 hours. Explicit client.files.upload(...) omits purpose and remains reusable. Remaining small files keep the single multipart round-trip.

From a Path

Filename and MIME type are inferred automatically.

From a file handle

Filename inferred from f.name.

From raw bytes

Multiple files

Each file becomes a files.<fieldName> multipart part. Mix files and scalar inputs freely; scalars ride in the input JSON part automatically.

Nested files are not extracted

Only top-level file values become multipart fields. Files inside lists or nested dicts stay in the input JSON part and the server will not see them as uploads:

Do not base64 yourself

The SDK picks multipart whenever it sees a Path, file-like object, or {"content": ..., "filename": ..., "mime_type": ...} dict. Plain strings pass through as scalar inputs.