Uploads
Send large files to the switchfile API. Signed upload URLs for the simple API, and upload tasks for jobs.
A file sent inside a multipart/form-data request can be up to 100 MB. For larger files, get a signed upload URL first and send the file there. The server reports the largest file in max_file_size, in bytes, in GET /v1/account and in every upload.
Simple API (v1)#
- POST /v1/uploads returns an
upload_idand a signedurl. - Send the file as the body of a
PUTto thaturl. Start beforeurl_expires_at(15 minutes). If the response listsheaders, send them with thePUT. - Convert it: POST /v1/convert with
{"upload_id": "...", "to": "..."}.
The same upload_id works for several conversions until expires_at, 24 hours later.
{
"upload_id": "7d1f0f7e-0b55-4a8e-8c5b-9d8e3f1a2b3c",
"method": "PUT",
"url": "https://...",
"headers": {},
"max_file_size": 1073741824,
"url_expires_at": "2026-11-06T18:15:00+00:00",
"expires_at": "2026-11-07T18:00:00+00:00"
}UPLOAD=$(curl -s https://api.switchfile.io/v1/uploads \
-H "Authorization: Bearer $SWITCHFILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "lecture.mov"}')
curl -X PUT --upload-file lecture.mov "$(echo "$UPLOAD" | jq -r .url)"
curl https://api.switchfile.io/v1/convert \
-H "Authorization: Bearer $SWITCHFILE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"upload_id\": \"$(echo "$UPLOAD" | jq -r .upload_id)\", \"to\": \"mp4\"}"import { readFile } from "node:fs/promises";
const headers = { Authorization: `Bearer ${process.env.SWITCHFILE_API_KEY}`, "Content-Type": "application/json" };
const upload = await (
await fetch("https://api.switchfile.io/v1/uploads", {
method: "POST",
headers,
body: JSON.stringify({ filename: "lecture.mov" }),
})
).json();
const put = await fetch(upload.url, { method: "PUT", headers: upload.headers, body: await readFile("lecture.mov") });
if (!put.ok) throw new Error(`upload failed: HTTP ${put.status}`);
const res = await fetch("https://api.switchfile.io/v1/convert", {
method: "POST",
headers,
body: JSON.stringify({ upload_id: upload.upload_id, to: "mp4" }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
console.log((await res.json()).id);import os
import requests
auth = {"Authorization": f"Bearer {os.environ['SWITCHFILE_API_KEY']}"}
upload = requests.post("https://api.switchfile.io/v1/uploads", headers=auth, json={"filename": "lecture.mov"}).json()
with open("lecture.mov", "rb") as f:
requests.put(upload["url"], headers=upload["headers"], data=f).raise_for_status()
conversion = requests.post(
"https://api.switchfile.io/v1/convert",
headers=auth,
json={"upload_id": upload["upload_id"], "to": "mp4"},
).json()
print(conversion["id"])For files of several GB, stream the file from disk instead of reading it into memory: in Node.js pass createReadStream(path) as body together with duplex: "half" and a Content-Length header.
DELETE /v1/uploads/{id} deletes an uploaded file right away. Conversions already created from it keep their own copy.
Jobs and tasks (v2)#
In a job, an import/upload task waits for the file. Its result.form describes an upload form:
"result": {
"form": {
"url": "https://api.switchfile.io/upload/c1f3a9d2-...?expires=...&max_file_size=...&signature=...",
"parameters": { "expires": 1762538401, "max_file_count": 1, "max_file_size": 1073741824, "signature": "..." }
}
}Send the file as multipart/form-data in the field file to result.form.url. The URL already holds the signed parameters, so the form fields in parameters are optional. No API key is needed for the upload.
curl "$FORM_URL" -F [email protected]Uploads through result.form are limited to 100 MB. For larger files the task also has result.upload with a signed PUT URL, the same as in the simple API. After the PUT, the task finishes on its own within a few seconds; call POST /v2/tasks/{id}/upload-complete to finish it right away.
curl -X PUT --upload-file lecture.mov "$UPLOAD_URL"
curl -X POST "https://api.switchfile.io/v2/tasks/$TASK_ID/upload-complete" \
-H "Authorization: Bearer $SWITCHFILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "lecture.mov"}'Small files as base64#
Jobs also take a file inline with the import/base64 task, up to 10 MB after decoding. It saves the extra upload request for small files:
{
"tasks": {
"import-1": { "operation": "import/base64", "file": "JVBERi0xLjQK...", "filename": "page.pdf" },
"convert-1": { "operation": "convert", "input": "import-1", "output_format": "png" },
"export-1": { "operation": "export/url", "input": "convert-1" }
}
}