Skip to main content

Overview

Most multimodal models on ModelRunner accept files (images, audio clips, videos) as URLs in their input. ModelRunner provides two upload patterns:
  • Single-part upload — one presigned PUT to S3, suitable for files up to ~5 GB.
  • Multipart upload — three-step flow with per-part presigned URLs, required for very large files or when you want resumability.
Both flows return a canonical media.modelrunner.ai URL that you can pass directly to any model input field that accepts a file.
The SDKs wrap the single-part flow as storage.upload() (JS) and upload_file() (Python). Use the raw HTTP flow below when you need multipart or when calling the API directly.

Single-part upload

A two-step flow: initiate → PUT bytes to the returned presigned URL.
1

Initiate the upload

POST /storage/upload/initiate returns a presigned upload_url and the canonical file_url to use as model input.
cURL
Response:
2

PUT the bytes to the presigned URL

Send the raw file body to upload_url with the same Content-Type. Do not add the Authorization header — the presigned URL carries its own credentials.
cURL
On success, file_url is immediately usable. Pass it to any model input that accepts a URL:
A file row is created at initiate-time. If you skip the PUT, the row remains as a benign orphan whose file_url will 404 until uploaded.

Setting an expiration

Uploads are kept until you delete them. To have one expire automatically, send the object-lifecycle header on the initiate call — the same header used for generated media:
The countdown starts at upload time. A file you later pass as a request input stops expiring, as does one you favorite or tag — see data retention for the full rules. For multipart, send the header on the complete call instead, since that is where the file is recorded. In the JavaScript SDK this is the lifecycle option:

Using the SDKs

Multipart upload (large files)

For multi-gigabyte videos or when you want resumability, use the three-step multipart flow.
1

Initiate the multipart upload

POST /storage/upload/initiate-multipart returns an uploadId, uploadKey, and the canonical fileUrl.
Response:
2

Upload each part

Split the file into parts (S3 requires each part except the last to be ≥ 5 MiB). For each part number starting at 1, request a presigned URL and PUT the part to it.
Capture the ETag header from each PUT response — S3 requires it (without quotes) when completing the upload.
3

Complete the upload

POST /storage/upload/complete finalizes the multipart upload and creates the file row.
The fileUrl this call returns is S3’s own location for the assembled object, which is not publicly readable. Use the fileUrl from step 1 (initiate-multipart) as the model input — that is the canonical media.modelrunner.ai URL, and it is live as soon as this call succeeds.

When the S3 host is blocked

Both flows above PUT the bytes straight to AWS S3. Clients that run behind an egress allowlist — AI assistants and agent sandboxes, mainly — often cannot reach that host and get a 403 with host_not_allowed. Two fallbacks stay on ModelRunner’s own domain:
  • Upload relay. Send "relay": true on Initiate Upload and the response carries a relay_upload_url alongside the usual upload_url. PUT the raw bytes there instead and we stream them to storage server-side. Same 5-minute window, same file_url, and no Authorization header — the token in the URL is the credential. Try the S3 URL first; the relay costs an extra hop.
  • Chunked inline upload. If neither host is reachable, POST /storage/upload/chunk takes the file as small base64 chunks and assembles it server-side. Capped at 50 MiB per file and slower than either PUT — a last resort.

Your asset library

Every upload and every model output becomes a file record you can list, search, and organize:
  • List Files — your library, filterable by bucket (upload / output / input), MIME type, tag, or favorite.
  • Get File by URL — resolve a media.modelrunner.ai URL you are holding back to its record, including which requests used it.
  • Favorite and tag files to organize them. Both also exempt a file from expiry, so something you meant to keep is not swept away — see data retention.
  • Delete File removes the record, not the stored bytes — and with the record gone there is nothing left to find the object by. Set an expiry at upload time for anything you want cleaned up automatically.
URLs you paste in from elsewhere are not recorded — only files that passed through ModelRunner storage.

Reference

Every endpoint except the relay takes the standard Authorization: Key <your_key> header — see API keys. Full request and response schemas live in the Platform API reference.