Create a batch
Creates up to 50 conversions with one request: all of them or none. With archive: "zip", archive.url offers all results as one ZIP file once every conversion is done. ?wait=N waits like POST /v1/convert. Supports Idempotency-Key.
https://api.switchfile.io/v1/batchesExample
curl "https://api.switchfile.io/v1/batches?wait=30" \
-H "Authorization: Bearer $SWITCHFILE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"archive": "zip",
"conversions": [
{
"url": "https://example.com/a.heic",
"to": "jpg"
},
{
"url": "https://example.com/b.heic",
"to": "jpg"
}
]
}'const res = await fetch("https://api.switchfile.io/v1/batches?wait=30", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SWITCHFILE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
archive: "zip",
conversions: [
{
url: "https://example.com/a.heic",
to: "jpg"
},
{
url: "https://example.com/b.heic",
to: "jpg"
}
]
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
console.log(await res.json());<?php
$ch = curl_init('https://api.switchfile.io/v1/batches?wait=30');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'archive' => 'zip',
'conversions' => [
[
'url' => 'https://example.com/a.heic',
'to' => 'jpg',
],
[
'url' => 'https://example.com/b.heic',
'to' => 'jpg',
],
],
]),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SWITCHFILE_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException("HTTP $status: $response");
}
print_r(json_decode($response, true));import os
import requests
res = requests.post(
"https://api.switchfile.io/v1/batches?wait=30",
headers={"Authorization": f"Bearer {os.environ['SWITCHFILE_API_KEY']}"},
json={
"archive": "zip",
"conversions": [
{
"url": "https://example.com/a.heic",
"to": "jpg",
},
{
"url": "https://example.com/b.heic",
"to": "jpg",
},
],
},
)
res.raise_for_status()
print(res.json())Parameters
Query parameters
waitnumberWait up to this many seconds until it is done (at most 30)
0 to 300 · example: 30
Headers
Idempotency-Keystring1 to 255 visible ASCII characters, for example a UUID. Send the request again with the same key after a timeout: nothing is created twice. Kept for 24 hours.
example: 6f1c2b8e-1d8e-4c55-9f0e-3f3f0b0a8f21
X-End-UserstringService keys only: an ID for the visitor you act for (1 to 128 characters: letters, digits and . _ : @ -). Quotas and rate limits then count per visitor.
X-End-User-IpstringRequired with X-End-User: the IP address of the visitor.
Request body
archivestringAlso offer all results as one ZIP file in archive.url
one of "zip"
conversionsBatchConversion[]required1 to 500 items
conversions[].filenamestringFile name of the input
1 to 255 characters
conversions[].fromstring (uuid)ID of an earlier conversion. Its input is converted again, without a new upload
conversions[].input_formatstringInput format, if the file name does not show it
1 to 20 characters
conversions[].optionsmap of string | number | booleanSettings for the conversion, for example { "quality": 80 }. null and an empty string count as not set. See the options per target format in the docs
at most 50 entries · keys match ^[a-z][a-z0-9_]{0,63}$
conversions[].presetstringID or name of a preset from the dashboard. It sets the target format and the options. Values in options override single settings of the preset. A preset with an input format only takes files of that format.
1 to 100 characters
conversions[].tostringTarget format, for example mp4. Required without preset. With preset it is optional and must match the preset
1 to 20 characters
conversions[].upload_idstring (uuid)ID of a file sent through POST /v1/uploads
conversions[].urlstringDownload the input from this public http or https URL
1 to 4096 characters
webhook_urlstringat most 4096 characters · matches ^https?://
Responses
200Done within wait
archiveBatchArchiverequiredarchive.expires_atstring | nullrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
archive.formatstringrequiredone of "zip"
archive.statusstringrequiredone of "pending", "ready", "empty"
archive.urlstring | nullrequiredSigned URL of the ZIP file, set when status is ready
conversionsConversion[]requiredconversions[].batch_idstring (uuid) | nullrequiredconversions[].created_atstringrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
conversions[].creditsstring (integer) | integerrequiredCredits used, set once the conversion is done
conversions[].download_urlstring | nullrequiredSigned URL of the first result file
conversions[].errorobject | nullrequiredconversions[].error.codestringrequiredconversions[].error.messagestringrequiredconversions[].expires_atstring | nullrequiredInput and result are deleted at this time
conversions[].finished_atstring | nullrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
conversions[].idstring (uuid)requiredconversions[].inputobjectrequiredconversions[].input.filenamestring | nullrequiredconversions[].input.formatstring | nullrequiredconversions[].input.sizestring (integer) | integerrequiredconversions[].linksobjectrequiredconversions[].links.selfstringrequiredconversions[].objectstringrequiredone of "conversion"
conversions[].optionsmap of anyrequiredkeys match ^(.*)$
conversions[].progressstring (integer) | integerrequiredProgress in percent
0 to 100
conversions[].resultobject | nullrequiredconversions[].result.filesConversionFile[]requiredconversions[].result.files[].filenamestringrequiredconversions[].result.files[].sizestring (integer) | integerrequiredconversions[].result.files[].urlstringrequiredSigned download URL, works without an API key until expires_at
conversions[].statusstringrequiredone of "queued", "processing", "finished", "failed"
conversions[].tostringrequiredcountsobjectrequiredcounts.failedstring (integer) | integerrequiredcounts.finishedstring (integer) | integerrequiredcounts.totalstring (integer) | integerrequiredcreated_atstringrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
idstring (uuid)requiredlinksobjectrequiredlinks.selfstringrequiredobjectstringrequiredone of "batch"
statusstringrequiredone of "processing", "finished"
200 application/json{ "id": "5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90", "object": "batch", "status": "finished", "counts": { "total": 1, "finished": 1, "failed": 0 }, "conversions": [ { "id": "0b8a7c1e-5d0f-4a51-9f39-2f7f4c1d9a10", "object": "conversion", "status": "finished", "progress": 100, "input": { "filename": "a.heic", "format": "heic", "size": 1843200 }, "to": "jpg", "options": {}, "result": { "files": [ { "filename": "a.jpg", "size": 402113, "url": "https://api.switchfile.io/files/2a6f8e1c-4b3d-4e7a-9c5f-8d1b0e2a4c67/a.jpg?expires=1762538401&signature=3f9c2a7d41e8b6c05d1f9e2a7b4c8d3e6f0a1b2c3d4e5f60718293a4b5c6d7e8" } ] }, "download_url": "https://api.switchfile.io/files/2a6f8e1c-4b3d-4e7a-9c5f-8d1b0e2a4c67/a.jpg?expires=1762538401&signature=3f9c2a7d41e8b6c05d1f9e2a7b4c8d3e6f0a1b2c3d4e5f60718293a4b5c6d7e8", "error": null, "credits": 1, "batch_id": "5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90", "created_at": "2026-11-06T18:00:00+00:00", "finished_at": "2026-11-06T18:00:02+00:00", "expires_at": "2026-11-07T18:00:02+00:00", "links": { "self": "https://api.switchfile.io/v1/conversions/0b8a7c1e-5d0f-4a51-9f39-2f7f4c1d9a10" } } ], "archive": { "format": "zip", "status": "ready", "url": "https://api.switchfile.io/v1/archives/5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90?expires=1762538401&signature=3f9c2a7d41e8b6c05d1f9e2a7b4c8d3e6f0a1b2c3d4e5f60718293a4b5c6d7e8", "expires_at": "2026-11-07T18:00:02+00:00" }, "created_at": "2026-11-06T18:00:00+00:00", "links": { "self": "https://api.switchfile.io/v1/batches/5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90" } }202Created, still running
archiveBatchArchiverequiredarchive.expires_atstring | nullrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
archive.formatstringrequiredone of "zip"
archive.statusstringrequiredone of "pending", "ready", "empty"
archive.urlstring | nullrequiredSigned URL of the ZIP file, set when status is ready
conversionsConversion[]requiredconversions[].batch_idstring (uuid) | nullrequiredconversions[].created_atstringrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
conversions[].creditsstring (integer) | integerrequiredCredits used, set once the conversion is done
conversions[].download_urlstring | nullrequiredSigned URL of the first result file
conversions[].errorobject | nullrequiredconversions[].error.codestringrequiredconversions[].error.messagestringrequiredconversions[].expires_atstring | nullrequiredInput and result are deleted at this time
conversions[].finished_atstring | nullrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
conversions[].idstring (uuid)requiredconversions[].inputobjectrequiredconversions[].input.filenamestring | nullrequiredconversions[].input.formatstring | nullrequiredconversions[].input.sizestring (integer) | integerrequiredconversions[].linksobjectrequiredconversions[].links.selfstringrequiredconversions[].objectstringrequiredone of "conversion"
conversions[].optionsmap of anyrequiredkeys match ^(.*)$
conversions[].progressstring (integer) | integerrequiredProgress in percent
0 to 100
conversions[].resultobject | nullrequiredconversions[].result.filesConversionFile[]requiredconversions[].result.files[].filenamestringrequiredconversions[].result.files[].sizestring (integer) | integerrequiredconversions[].result.files[].urlstringrequiredSigned download URL, works without an API key until expires_at
conversions[].statusstringrequiredone of "queued", "processing", "finished", "failed"
conversions[].tostringrequiredcountsobjectrequiredcounts.failedstring (integer) | integerrequiredcounts.finishedstring (integer) | integerrequiredcounts.totalstring (integer) | integerrequiredcreated_atstringrequiredISO 8601 timestamp, for example 2026-11-06T18:00:00+00:00
idstring (uuid)requiredlinksobjectrequiredlinks.selfstringrequiredobjectstringrequiredone of "batch"
statusstringrequiredone of "processing", "finished"
202 application/json{ "id": "5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90", "object": "batch", "status": "processing", "counts": { "total": 1, "finished": 0, "failed": 0 }, "conversions": [ { "id": "0b8a7c1e-5d0f-4a51-9f39-2f7f4c1d9a10", "object": "conversion", "status": "processing", "progress": 0, "input": { "filename": "a.heic", "format": "heic", "size": 1843200 }, "to": "jpg", "options": {}, "result": null, "download_url": null, "error": null, "credits": null, "batch_id": "5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90", "created_at": "2026-11-06T18:00:00+00:00", "finished_at": null, "expires_at": null, "links": { "self": "https://api.switchfile.io/v1/conversions/0b8a7c1e-5d0f-4a51-9f39-2f7f4c1d9a10" } } ], "archive": { "format": "zip", "status": "pending", "url": null, "expires_at": null }, "created_at": "2026-11-06T18:00:00+00:00", "links": { "self": "https://api.switchfile.io/v1/batches/5c0f1d7a-6a54-4a49-b3c5-0c7d6a1e2f90" } }401The API key is missing or not valid
UNAUTHENTICATED401 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-unauthenticated", "title": "Unauthenticated", "status": 401, "code": "UNAUTHENTICATED", "detail": "Missing or invalid API key." }402Today's free quota is used up and there are not enough credits
CREDITS_EXCEEDED402 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-credits-exceeded", "title": "Credits exceeded", "status": 402, "code": "CREDITS_EXCEEDED", "detail": "Today's free quota is used up and there are not enough credits left." }403Not allowed: a signed URL is wrong or expired, or X-End-User was sent without a service key
END_USER_NOT_ALLOWED403 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-end-user-not-allowed", "title": "End user not allowed", "status": 403, "code": "END_USER_NOT_ALLOWED", "detail": "The X-End-User header is only allowed with a service key." }404Does not exist for this account
NOT_FOUND404 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-not-found", "title": "Not found", "status": 404, "code": "NOT_FOUND", "detail": "Upload not found.", "index": 2 }409Conflict with the current state
IDEMPOTENCY_KEY_IN_USE409 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-idempotency-key-in-use", "title": "Idempotency key in use", "status": 409, "code": "IDEMPOTENCY_KEY_IN_USE", "detail": "A request with this Idempotency-Key is still running." }411The request has a body but no Content-Length header
LENGTH_REQUIRED411 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-length-required", "title": "Length required", "status": 411, "code": "LENGTH_REQUIRED", "detail": "A Content-Length header is required for this request." }413The request or the file is too large
FILE_TOO_LARGE413 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-file-too-large", "title": "File too large", "status": 413, "code": "FILE_TOO_LARGE", "detail": "The file is larger than the allowed maximum." }422Invalid data. index names the failing entry
UNSUPPORTED_PAIR422 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-unsupported-pair", "title": "Unsupported pair", "status": 422, "code": "UNSUPPORTED_PAIR", "detail": "Converting txt to mp4 is not supported.", "index": 1 }429Too many requests or a daily quota is used up. See Retry-After
RATE_LIMIT_EXCEEDED429 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-rate-limit-exceeded", "title": "Rate limit exceeded", "status": 429, "code": "RATE_LIMIT_EXCEEDED", "detail": "Too many requests. Try again in 12 seconds." }