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.
Initiate the upload
POST /storage/upload/initiate returns a presigned upload_url and the canonical file_url to use as model input.curl -X POST "https://api.modelrunner.run/storage/upload/initiate" \
-H "Authorization: Key $MODELRUNNER_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_name": "input.png",
"content_type": "image/png",
"size": 482917
}'
Response:{
"upload_url": "https://s3.amazonaws.com/...?X-Amz-Signature=...",
"file_url": "https://media.modelrunner.ai/abc123-input.png"
}
| Field | Required | Notes |
|---|
file_name | yes | Original filename; preserved (with a random prefix). |
content_type | yes | MIME type. Set the same value on the PUT below. |
size | no | Byte size, for validation. |
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 -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/png" \
--data-binary @input.png
On success, file_url is immediately usable. Pass it to any model input that accepts a URL:{ "image_url": "https://media.modelrunner.ai/abc123-input.png" }
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.
Using the SDKs
import { modelrunner } from "@modelrunner/client";
import fs from "node:fs";
const buf = fs.readFileSync("./input.png");
const fileUrl = await modelrunner.storage.upload(new Blob([buf]));
const result = await modelrunner.subscribe("swook/inspyrenet", {
input: { image_path: fileUrl },
});
Multipart upload (large files)
For multi-gigabyte videos or when you want resumability, use the three-step multipart flow.
Initiate the multipart upload
POST /storage/upload/initiate-multipart returns an uploadId, uploadKey, and the canonical fileUrl.curl -X POST "https://api.modelrunner.run/storage/upload/initiate-multipart" \
-H "Authorization: Key $MODELRUNNER_KEY" \
-H "Content-Type: application/json" \
-d '{ "file_name": "clip.mp4", "content_type": "video/mp4", "size": 1500000000 }'
Response:{
"fileUrl": "https://media.modelrunner.ai/abc123-clip.mp4",
"uploadId": "2~aBcDeF...",
"uploadKey": "abc123-clip.mp4"
}
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.curl -G "https://api.modelrunner.run/storage/upload/multipart-url" \
-H "Authorization: Key $MODELRUNNER_KEY" \
--data-urlencode "uploadKey=$UPLOAD_KEY" \
--data-urlencode "uploadId=$UPLOAD_ID" \
--data-urlencode "partNumber=1"
# → { "presignedUrl": "https://s3.amazonaws.com/...&partNumber=1&..." }
curl -X PUT "$PRESIGNED_URL" --data-binary @part-1.bin -D headers.txt
# Read the ETag from the response headers; you'll need it for `complete`.
Capture the ETag header from each PUT response — S3 requires it (without quotes) when completing the upload.
Complete the upload
POST /storage/upload/complete finalizes the multipart upload and creates the file row.curl -X POST "https://api.modelrunner.run/storage/upload/complete" \
-H "Authorization: Key $MODELRUNNER_KEY" \
-H "Content-Type: application/json" \
-d '{
"uploadId": "'"$UPLOAD_ID"'",
"uploadKey": "'"$UPLOAD_KEY"'",
"parts": [
{ "partNumber": 1, "etag": "e1..." },
{ "partNumber": 2, "etag": "e2..." }
]
}'
# → { "fileUrl": "https://media.modelrunner.ai/abc123-clip.mp4" }
The returned fileUrl is now usable as a model input.
Reference
| Method | Path | Body / Query | Returns |
|---|
| POST | /storage/upload/initiate | { file_name, content_type, size? } | { upload_url, file_url } |
| POST | /storage/upload/initiate-multipart | { file_name, content_type, size? } | { fileUrl, uploadId, uploadKey } |
| GET | /storage/upload/multipart-url | ?uploadKey&uploadId&partNumber | { presignedUrl } |
| POST | /storage/upload/complete | { uploadId, uploadKey, parts: [{ partNumber, etag }] } | { fileUrl } |
All endpoints require the standard Authorization: Key <your_key> header. See API keys.