API
Jobs
A job converts its inputs to one format, and can read a file's refs or edit it on the way. It runs in the background and lists the files it made in outputs.
Start a job
POST /v1/jobs with the inputs and the format to make. With Prefer: wait=30 the answer waits up to 30 seconds: 200 with the finished job, or 202 with the job as it is and its URL in Location.
See Waiting and retries for jobs that take longer, and for sending the same request twice safely.
$ export CV_API_KEY=cv_sk_…Set your key once. Every cv command reads it.
$ cv convert lease.docx lease.pdfstderrlease.pdf (21480 bytes) -> lease.pdfRequest fields
| Field | |
|---|---|
| inputs | Ids of ready files, up to 5,000. A job with refs, or an edit with a rev, takes one. |
| to | The format to make, as an id, alias, extension or MIME type. See Formats. |
| options | The options of the conversion. The options schema of each transform in the catalog says which it takes. See Options. |
| refs | Read the refs view: {} for all of it, or with outline, scope or max_chars. See Read a big file. |
| edit | {"rev": …, "edits": […]} to change the file. A job reads refs or edits, not both. See Edit a file. |
| output | shape: one joins the inputs into one file, and many converts each one. ttl_s keeps the outputs for less than 24 hours. |
| webhook | A public http or https URL to call when the job ends, up to 2,048 bytes. See Webhooks. |
| dry_run | Check the request and name the conversions, without running them. |
| metadata | Any JSON of yours, up to 16 KB, kept on the job. |
The job object
The job also echoes what you sent: to, options, refs, output, webhook and metadata. Options that hold a secret, such as a password, are not shown.
| Field | |
|---|---|
| status | queued, running, done, failed or canceled. |
| inputs | Each input file with its rev once the job has read it. |
| transforms | The conversions the job runs, each with its id and version. |
| outputs | The first 100 files the job made, in the order of index, each a file object with a url. GET /v1/jobs/{id}/outputs lists them all. |
| output_count | How many files the job made. When it is more than 100, outputs holds only the first 100. |
| archive | When a job made more than one file, a zip of them all with its size and url, up to 1 GB. |
| changes | What an edit changed, for each output. See Edit a file. |
| next | The scope to read next, when max_chars cut the refs view. |
| warnings | What you should know about a result that worked, such as a formula whose result could not be computed. Each has a code, a message, and ref or edit when it is about one place or one edit. See Warnings. |
| progress | From 0 to 1. |
| error | Why the job failed. See Error codes. |
| timings | Milliseconds the job spent in each stage. |
| created_at | When the job was created. |
| started_at | When a worker started it. |
| finished_at | When it ended. |
Several outputs
Some conversions make one file per page or per sheet, such as a PDF to PNG. Each output has its index, and the job's archive holds them all in one zip.
A job shows its first 100 outputs in outputs, and output_count says how many it made. GET /v1/jobs/{id}/outputs lists them all in the order of index, up to limit (1 to 100) at a time. Pass next_cursor as cursor for the next page.
output.shape set to one asks for exactly one file. When the conversion would make several, the job fails with invalid_request and a suggestion to pick one page.
Several inputs are converted one by one unless output.shape is one, which joins them into one file. See Join several files.
$ curl https://api.convert.dev/v1/jobs/job_01JC9W5D3K8N2Q6T9V1M4R7XAE/outputs?limit=100 \ -H "Authorization: Bearer $CV_API_KEY"response5 lines
{ "object": "list", "data": [{"object": "file", "id": "file_01JC9W…", "name": "page-1.png", "index": 0, "url": "https://…", …}, …], "next_cursor": "…"}Check a request first
dry_run checks the request and names the conversions it would run, with their versions. Nothing runs and nothing is charged.
An option the conversion does not take, or a target that does not exist, fails here as it would in a real job.
$ curl -X POST https://api.convert.dev/v1/jobs \ -H "Authorization: Bearer $CV_API_KEY" \ -H "Content-Type: application/json" \ -d '{"inputs": ["file_01JC9W3TQ6V8ZK2N5R7M4H1XEB"], "to": "pdf", "dry_run": true}'response6 lines
{ "object": "preview", "inputs": ["file_01JC9W3TQ6V8ZK2N5R7M4H1XEB"], "to": "pdf", "transforms": [{"id": "docx>pdf", "version": "75f37498"}]}List, cancel and delete
GET /v1/jobs lists jobs newest first, up to limit (1 to 100) at a time. status filters them, such as queued,running, input lists the jobs that read one file, and metadata lists the jobs whose metadata has every field of a JSON object, such as {"agent":"triage"}. A page holds fewer jobs when they have many outputs, so follow next_cursor for the rest. A limit outside 1 to 100, or a status the API does not know, fails with invalid_request.
POST /v1/jobs/{id}/cancel cancels a job and returns it, canceled unless it had already finished. Canceling a finished job changes nothing, so it is safe to send again. A job canceled within its first minute of work costs nothing.
DELETE /v1/jobs/{id} deletes a finished job and answers 204. Its request, metadata, warnings, changes, error and the files it made go with it. Its inputs stay, so delete them as files. A job that is queued or running fails with conflict, so cancel it first. What the job cost stays in your usage.
$ curl https://api.convert.dev/v1/jobs?status=queued,running \ -H "Authorization: Bearer $CV_API_KEY"$ curl -X POST https://api.convert.dev/v1/jobs/job_01JC9W5D3K8N2Q6T9V1M4R7XAE/cancel \ -H "Authorization: Bearer $CV_API_KEY"$ curl -X DELETE https://api.convert.dev/v1/jobs/job_01JC9W5D3K8N2Q6T9V1M4R7XAE \ -H "Authorization: Bearer $CV_API_KEY"Updated 3 November 2026