- Home
- API Reference
API Reference
Convert any file programmatically. Import files, apply conversions, and export results - all in a single API call.
Overview
The RunConvert API lets you convert any file programmatically. Create jobs with chained tasks - import a file, convert it, and export the result - all in a single request.
Every pipeline follows the same shape: import → convert → export. Tasks reference each other by name using the input field, and the API executes them in dependency order automatically.
Base URL
Request format
All request bodies must be JSON. Set Content-Type: application/json on every POST/PATCH request.
Discover supported formats
Call GET /v3/operations (no auth required) to find which input formats are supported, what each can be converted to, and which engines and options are available. See the Discover formats section for full details.
# Convert mp4 → mp3 in one request
curl -X POST https://api.runconvert.com/v3/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"tasks": {
"import-1": {
"operation": "import/url",
"url": "https://example.com/video.mp4"
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "mp4",
"output_format": "mp3"
},
"export-1": {
"operation": "export/url",
"input": "convert-1"
}
}
}'Authentication
All API requests require bearer token authentication. Include your API key in the Authorization header of every request.
Never expose API keys in client-side code or public repositories. Use environment variables and keep keys server-side only.
Revoking keys
Revoke any key from Dashboard → API Keys. Revoked keys return 401 immediately.
curl https://api.runconvert.com/v3/jobs \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json"{
"code": "UNAUTHORIZED",
"message": "Sign in to view jobs."
}Quickstart
Convert an MP4 video to MP3 audio from a public URL in four steps.
Import
Define an import/url task pointing at your source file.
Convert
Add a convert task. Both input_format and output_format are required.
Export
Add an export/url task to get a download link for the output.
Poll or webhook
Poll GET /jobs/{id} until status is "finished", or configure a webhook to receive a callback.
Not sure which formats are supported? Call GET /v3/operations?input=mp4 to see all valid output formats for any input extension, along with credit costs.
curl -X POST https://api.runconvert.com/v3/jobs \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"tag": "mp4-to-mp3",
"tasks": {
"import-1": {
"operation": "import/url",
"url": "https://example.com/video.mp4"
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "mp4",
"output_format": "mp3"
},
"export-1": {
"operation": "export/url",
"input": "convert-1"
}
}
}'// Created - tasks are dispatched immediately
{
"id": "job_01hx4k9m2p",
"status": "processing",
"tag": "mp4-to-mp3",
"credits_used": 1,
"created_at": "2026-05-01T10:23:00Z"
}
// Poll GET /v3/jobs/job_01hx4k9m2p?include=tasks
// until status === "finished"
{
"id": "job_01hx4k9m2p",
"status": "finished",
"credits_used": 1,
"started_at": "2026-05-01T10:23:00Z",
"ended_at": "2026-05-01T10:23:04Z",
"expires_at": "2026-05-02T10:23:04Z",
"tasks": [
{
"name": "export-1",
"operation": "export/url",
"status": "finished",
"result": {
"files": [{
"filename": "video.mp3",
"url": "https://cdn.runconvert.com/dl/...",
"size": 4821200,
"created_at": "2026-05-01T10:23:03Z"
}]
}
}
]
}Jobs
A job is a container for one or more named tasks. Tasks reference each other by name via the input field. The API resolves the dependency graph and executes tasks in the correct order.
Job statuses
Create a job
| Param | Type | Description |
|---|---|---|
| tasksreq | object | Named task definitions. Keys are task names referenced by downstream tasks via input. Names must be alphanumeric with hyphens or underscores (max 64 chars). |
| tag | string | Optional label for filtering in the list endpoint. |
| metadata | object | Arbitrary key-value data stored with the job. |
List jobs
| Param | Type | Description |
|---|---|---|
| filter[status] | string | Filter by status: waiting | processing | finished | error |
| filter[tag] | string | Filter by tag. |
| include | string | Pass "tasks" to embed task objects in each job. |
| page | integer | Page number. Default: 1. |
| per_page | integer | Results per page. Default: 100. |
Get a job
| Param | Type | Description |
|---|---|---|
| include | string | Pass "tasks" to include task objects in the response. |
Cancel a job
Cancels all pending tasks. Credits are refunded for API key jobs.
Delete a job
# List finished jobs
curl "https://api.runconvert.com/v3/jobs?filter[status]=finished&per_page=10" \
-H "Authorization: Bearer sk_live_..."
# Get a specific job with its tasks
curl "https://api.runconvert.com/v3/jobs/job_01hx4k9m2p?include=tasks" \
-H "Authorization: Bearer sk_live_..."
# Cancel a job
curl -X POST https://api.runconvert.com/v3/jobs/job_01hx4k9m2p/cancel \
-H "Authorization: Bearer sk_live_..."{
"id": "job_01hx4k9m2p",
"status": "finished",
"tag": "mp4-to-mp3",
"credits_used": 1,
"credit_type": "api",
"metadata": {},
"created_at": "2026-05-01T10:23:00Z",
"started_at": "2026-05-01T10:23:00Z",
"ended_at": "2026-05-01T10:23:04Z",
"expires_at": "2026-05-02T10:23:04Z"
}Tasks
Tasks are the individual steps within a job. Each task has an operation plus operation-specific parameters. The input field references the upstream task name - it accepts either a string or an array of strings.
Task statuses
ignore_error
Set ignore_error: true on a task to let the job continue even if that task hits an error. Downstream tasks that depend on a failed task are skipped.
List tasks
| Param | Type | Description |
|---|---|---|
| filter[job_id] | string | Filter by job ID. |
| filter[status] | string | Filter by status: waiting | processing | finished | error |
| filter[operation] | string | Filter by operation type. |
| include | string | Comma-separated extras: retries, payload, depends_on_tasks |
| page | integer | Page number. Default: 1. |
| per_page | integer | Results per page. Default: 100. |
Get / Cancel / Retry a task
Only tasks in error status can be retried.
{
"id": "task_9xkq2v",
"job_id": "job_01hx4k9m2p",
"name": "convert-1",
"operation": "convert",
"status": "finished",
"percent": 100,
"message": "",
"engine": "ffmpeg",
"engine_version": "6.1",
"credits": 1,
"ignore_error": false,
"input": ["import-1"],
"result": {
"files": [{
"filename": "video.mp3",
"size": 4821200,
"url": "https://cdn.runconvert.com/...",
"created_at": "2026-05-01T10:23:03Z"
}]
},
"created_at": "2026-05-01T10:23:00Z",
"started_at": "2026-05-01T10:23:00Z",
"ended_at": "2026-05-01T10:23:03Z",
"expires_at": "2026-05-02T10:23:03Z"
}import/url
Import a file from any publicly accessible URL. RunConvert fetches the file at job execution time.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "import/url". |
| urlreq | string | Publicly accessible URL of the file to import. |
| filename | string | Override the filename. Defaults to the last segment of the URL path. |
{
"tasks": {
"import-1": {
"operation": "import/url",
"url": "https://example.com/video.mp4",
"filename": "video.mp4"
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "mp4",
"output_format": "mp3"
}
}
}import/upload
Get a presigned upload URL for direct file uploads. Create the job - the API returns an upload_url immediately in the task object. PUT your file to that URL, and the job proceeds automatically once the upload is received.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "import/upload". |
| filenamereq | string | Name of the file being uploaded, including extension. |
The upload URL expires after a short window (5–15 minutes depending on your plan). Upload promptly after job creation.
{
"tasks": {
"import-1": {
"operation": "import/upload",
"filename": "video.mp4"
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "mp4",
"output_format": "mp3"
},
"export-1": { "operation": "export/url", "input": "convert-1" }
}
}// The import task immediately has an upload_url
{
"id": "job_01hx4k9m2p",
"status": "waiting",
"tasks": [{
"name": "import-1",
"operation": "import/upload",
"status": "waiting",
"upload_url": "https://storage.runconvert.com/upload/task_abc?token=...",
"upload_deadline": "2026-05-01T10:38:00Z"
}]
}# PUT the file to the upload_url
curl -X PUT "https://storage.runconvert.com/upload/task_abc?token=..." \
-H "Content-Type: video/mp4" \
--data-binary @video.mp4
# Job resumes automatically once upload is receivedimport/base64
Embed a file directly in the request body as base64. Best for small files only.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "import/base64". |
| filereq | string | Base64-encoded file content. |
| filenamereq | string | Filename including extension - used to determine input format. |
For files larger than ~1 MB use import/upload or import/url to avoid large request bodies.
{
"tasks": {
"import-1": {
"operation": "import/base64",
"filename": "image.png",
"file": "iVBORw0KGgoAAAANSUhEUgAA..."
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "png",
"output_format": "webp"
},
"export-1": { "operation": "export/url", "input": "convert-1" }
}
}import/s3
Import a file directly from an AWS S3 bucket using the credentials you provide.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "import/s3". |
| bucketreq | string | S3 bucket name. |
| keyreq | string | Object key (path) within the bucket. |
| regionreq | string | AWS region, e.g. us-east-1. |
| access_key_id | string | AWS access key ID. |
| secret_access_key | string | AWS secret access key. |
{
"tasks": {
"import-1": {
"operation": "import/s3",
"bucket": "my-media-files",
"key": "uploads/2026/video.mp4",
"region": "us-east-1",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI/K7MDENG..."
},
"convert-1": {
"operation": "convert",
"input": "import-1",
"input_format": "mp4",
"output_format": "mp3"
}
}
}convert
Convert a file from one format to another. Supports 3,000+ format pairs across video, audio, image, document, archive, ebook, font, and CAD categories.
Both input_format and output_format are required. Omitting either returns a 400 error. Use GET /v3/operations?input=mp4 to discover valid output formats for any input extension.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "convert". |
| inputreq | string | Name of the import task whose output to convert. |
| input_formatreq | string | Source format extension, e.g. mp4, png, docx. |
| output_formatreq | string | Target format extension, e.g. mp3, webp, pdf. |
| preferred_engine | string | Request a specific engine when multiple are available for this pair. Falls back to the default if not found. |
| options | object | Engine-specific settings (e.g. bitrate, quality, width). Fetch available options from GET /v3/operations?input=X&output=Y. |
| ignore_error | boolean | If true, the job continues even if this task fails. |
const res = await fetch("https://api.runconvert.com/v3/jobs", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.RUNCONVERT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
tasks: {
"import-1": {
operation: "import/url",
url: "https://example.com/video.mp4",
},
"convert-1": {
operation: "convert",
input: "import-1",
input_format: "mp4",
output_format: "mp3",
options: { bitrate: "192k" },
},
"export-1": {
operation: "export/url",
input: "convert-1",
},
},
}),
});
const job = await res.json();
console.log(job.id);Discover formats
GET /v3/operations is a public endpoint (no auth required) that lets you discover supported formats, valid output targets for any input extension, and the engines and options available for each conversion pair.
| Param | Type | Description |
|---|---|---|
| input | string | Input format extension (e.g. mp4). Returns all valid output formats plus credit cost. |
| output | string | Combined with input - returns available engines and their options for this specific pair. |
| category | string | Filter all formats by category: video | audio | image | document | ebook | presentation | spreadsheet | vector | cad | archive | font |
Using options in a convert task
The engines[].options array tells you what you can pass as the options object on a convert task - including the field name, type, description, and supported values.
# All output formats for mp4 (no auth needed)
curl "https://api.runconvert.com/v3/operations?input=mp4"
# Engines + options for mp4 → mp3
curl "https://api.runconvert.com/v3/operations?input=mp4&output=mp3"
# All video input formats
curl "https://api.runconvert.com/v3/operations?category=video"
# All formats across all categories
curl "https://api.runconvert.com/v3/operations"// GET /v3/operations?input=mp4
{
"format": "mp4",
"category": "video",
"outputs": [
{ "format": "mp3", "category": "audio", "engine": "ffmpeg", "credits": 1 },
{ "format": "wav", "category": "audio", "engine": "ffmpeg", "credits": 1 },
{ "format": "webm", "category": "video", "engine": "ffmpeg", "credits": 1 },
{ "format": "gif", "category": "image", "engine": "ffmpeg", "credits": 2 }
]
}
// GET /v3/operations?input=mp4&output=mp3
{
"input": "mp4",
"output": "mp3",
"engines": [{
"name": "ffmpeg",
"credits": 1,
"options": [
{
"name": "bitrate",
"type": "string",
"description": "Audio bitrate",
"supported_values": ["64k", "96k", "128k", "192k", "256k", "320k"]
},
{
"name": "sample_rate",
"type": "integer",
"description": "Sample rate in Hz",
"supported_values": [22050, 44100, 48000]
}
]
}]
}export/url
Generate a temporary public download URL for the converted file.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "export/url". |
| inputreq | string | Name of the convert task to export. |
| filename | string | Override the output filename. |
// Task definition
{
"export-1": {
"operation": "export/url",
"input": "convert-1",
"filename": "converted.mp3"
}
}
// Result in finished job
{
"name": "export-1",
"status": "finished",
"result": {
"files": [{
"filename": "converted.mp3",
"size": 4821200,
"url": "https://cdn.runconvert.com/dl/abc123/converted.mp3",
"created_at": "2026-05-01T10:23:03Z"
}]
}
}export/s3
Save the converted file directly to an AWS S3 bucket.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "export/s3". |
| inputreq | string | Name of the convert task to export. |
| bucketreq | string | Target S3 bucket name. |
| keyreq | string | Object key (path) to write in the bucket. |
| regionreq | string | AWS region. |
| access_key_id | string | AWS access key ID. |
| secret_access_key | string | AWS secret access key. |
| acl | string | "private" | "public-read". Default: "private". |
{
"tasks": {
"export-1": {
"operation": "export/s3",
"input": "convert-1",
"bucket": "my-output-bucket",
"key": "converted/video.mp3",
"region": "us-east-1",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI...",
"acl": "private"
}
}
}export/base64
Return the converted file inline in the job result as base64. Best for small files only.
| Param | Type | Description |
|---|---|---|
| operationreq | string | Must be "export/base64". |
| inputreq | string | Name of the convert task to export. |
Avoid export/base64 for large files - use export/url instead.
{
"name": "export-1",
"status": "finished",
"result": {
"files": [{
"filename": "image.webp",
"content": "UklGRlYAAABXRUJQVlA4...",
"size": 48201
}]
}
}Webhooks
Webhooks deliver HTTP POST notifications to your endpoint when jobs and tasks change state - eliminating polling.
Supported events
job.createdA new job was acceptedjob.processingThe first task in the job started runningjob.finishedAll tasks completed successfullyjob.errorOne or more tasks failed (without ignore_error)task.finishedA single task completed successfullytask.errorA single task failedPayload structure
Every delivery POSTs JSON with an event string plus either a job or task object depending on the event type.
Signature verification
Every delivery includes an X-RunConvert-Signature header - an HMAC-SHA256 of the raw request body signed with your webhook secret. Always verify this before processing the payload.
// event: job.finished
{
"event": "job.finished",
"job": {
"id": "job_01hx4k9m2p",
"status": "finished",
"tag": "mp4-to-mp3",
"credits_used": 1,
"created_at": "2026-05-01T10:23:00Z",
"ended_at": "2026-05-01T10:23:04Z",
"expires_at": "2026-05-02T10:23:04Z"
}
}// event: task.finished
{
"event": "task.finished",
"task": {
"id": "task_9xkq2v",
"job_id": "job_01hx4k9m2p",
"name": "export-1",
"operation": "export/url",
"status": "finished",
"credits": 0,
"result": {
"files": [{
"filename": "video.mp3",
"url": "https://cdn.runconvert.com/...",
"size": 4821200
}]
}
}
}Create Webhook
| Param | Type | Description |
|---|---|---|
| urlreq | string | HTTPS URL that will receive POST requests. |
| events | string[] | Event types to subscribe to. Omit to receive all events. |
| description | string | Human-readable label for this endpoint. |
The full secret is returned once on creation only. Store it securely - subsequent reads return a masked value.
curl -X POST https://api.runconvert.com/v3/webhooks \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://myapp.com/webhooks/runconvert",
"events": ["job.finished", "job.error"],
"description": "Production notifications"
}'{
"id": "wh_01hx4k9m2p",
"url": "https://myapp.com/webhooks/runconvert",
"description": "Production notifications",
"events": ["job.finished", "job.error"],
"secret": "whsec_abc123...",
"enabled": true,
"created_at": "2026-05-01T10:00:00Z",
"updated_at": "2026-05-01T10:00:00Z"
}List & Get Webhooks
Returns all webhook endpoints for your account.
Returns a single endpoint. The secret is masked after creation.
Test ping
Sends a test delivery to the endpoint URL to verify it is reachable.
{
"id": "wh_01hx4k9m2p",
"url": "https://myapp.com/webhooks/runconvert",
"description": "Production notifications",
"events": ["job.finished", "job.error"],
"secret": "whsec_abc***",
"enabled": true,
"created_at": "2026-05-01T10:00:00Z",
"updated_at": "2026-05-01T10:00:00Z"
}Update Webhook
Update any combination of fields. Only provided fields are changed.
| Param | Type | Description |
|---|---|---|
| url | string | New HTTPS endpoint URL. |
| events | string[] | Replace the event subscription list. |
| description | string | Update the label. |
| enabled | boolean | Set to false to pause delivery without deleting the endpoint. |
# Pause a webhook
curl -X PATCH https://api.runconvert.com/v3/webhooks/wh_01hx4k9m2p \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "enabled": false }'
# Change subscribed events
curl -X PATCH https://api.runconvert.com/v3/webhooks/wh_01hx4k9m2p \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{ "events": ["job.finished", "job.error", "task.error"] }'Delete Webhook
Permanently removes a webhook endpoint. No further events will be delivered.
curl -X DELETE \
https://api.runconvert.com/v3/webhooks/wh_01hx4k9m2p \
-H "Authorization: Bearer sk_live_..."
# 204 No Content on successErrors
All error responses include a JSON body with a machine-readable code and a human-readable message.
HTTP status codes
200OKRequest succeeded201CreatedResource created204No ContentSuccessful deletion400Bad RequestInvalid body, missing required field, or unsupported format pair401UnauthorizedMissing or invalid API key / sign-in required403ForbiddenResource belongs to another account404Not FoundResource does not exist422UnprocessableInsufficient credits, no workers available429Too Many RequestsDaily credit limit or active job limit exceeded500Server ErrorRetry with exponential backoffApplication error codes
UNAUTHORIZEDMissing or invalid API keySIGN_IN_REQUIREDThis operation requires a signed-in accountVALIDATION_ERRORInvalid body or missing required field (e.g. input_format)INVALID_OPERATIONUnknown operation or unsupported input→output pairJOB_NOT_FOUNDJob ID does not existJOB_FORBIDDENJob belongs to another accountTASK_NOT_FOUNDTask ID does not existTASK_NOT_RETRYABLEOnly error tasks can be retriedBILLING_INSUFFICIENT_CREDITSAccount has no remaining creditsNO_WORKERS_AVAILABLENo conversion workers available right nowGUEST_DAILY_LIMIT_REACHEDGuest daily limit reached (10/day) - sign up for moreFREE_TIER_DAILY_LIMIT_REACHEDFree account daily limit reached - upgrade for unlimitedACTIVE_JOB_LIMIT_REACHEDToo many active jobs - wait for existing ones to finishDEVICE_BLOCKEDThis device has been blocked// 400 - missing input_format
{
"code": "VALIDATION_ERROR",
"message": "task \"convert-1\": input_format is required for convert tasks"
}
// 400 - unsupported format pair
{
"code": "INVALID_OPERATION",
"message": "operation \"convert\": conversion from \"mp4\" to \"xyz\" is not supported"
}
// 422 - insufficient credits
{
"code": "BILLING_INSUFFICIENT_CREDITS",
"message": "Insufficient credits."
}
// 429 - guest daily limit
{
"code": "GUEST_DAILY_LIMIT_REACHED",
"message": "Daily limit reached (10/day). Sign up for a free account to get more."
}Rate Limits
RunConvert uses a credit-based daily limit system. Each conversion costs a number of credits (visible via GET /v3/operations?input=X&output=Y). API key jobs additionally deduct from your team credit balance.
Daily credit limits
Active job limit
There is a per-account limit on concurrent active jobs to keep the queue healthy. Wait for existing jobs to reach finished or error before creating new ones if you hit this limit.
// 429 - guest daily limit
{
"code": "GUEST_DAILY_LIMIT_REACHED",
"message": "Daily limit reached (10/day). Sign up for a free account to get more."
}
// 429 - free account limit
{
"code": "FREE_TIER_DAILY_LIMIT_REACHED",
"message": "Daily limit reached (20/day). Upgrade for unlimited conversions."
}
// 429 - too many concurrent jobs
{
"code": "ACTIVE_JOB_LIMIT_REACHED",
"message": "Too many active jobs. Wait for existing jobs to finish before creating new ones."
}SDKs & Libraries
Official SDKs are coming soon. In the meantime, the REST API works with any HTTP client in any language.
Node.js / TypeScript
Use native fetch or any HTTP library (axios, got, ky).
Python
Use requests or httpx.
Community libraries
Community-maintained SDKs will be listed here as they become available. Building one? Let us know.
async function waitForJob(jobId: string, apiKey: string) {
while (true) {
const res = await fetch(
`https://api.runconvert.com/v3/jobs/${jobId}?include=tasks`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
const job = await res.json();
if (job.status === "finished") return job;
if (job.status === "error") throw new Error(`Job failed: ${jobId}`);
// Poll every 2 seconds (or use webhooks instead)
await new Promise(r => setTimeout(r, 2000));
}
}
const job = await waitForJob("job_01hx4k9m2p", process.env.RUNCONVERT_API_KEY!);
const exportTask = job.tasks.find((t: any) => t.operation === "export/url");
console.log(exportTask.result.files[0].url);