---
name: api2convert-api
description: >-
  Convert, compress, and transform files (images, video, audio, documents, ebooks,
  archives) programmatically through the api2convert REST API. Use this whenever the user
  wants to convert a file from one format to another, run OCR, extract or re-encode
  audio/video, resize or optimize media, capture a website screenshot, merge or compress
  files, or build an integration against api2convert.com — or whenever you see an
  `x-oc-api-key` or a conversion "job". Covers authentication, the
  job → input → conversion → output lifecycle, polling and webhook callbacks, discovering
  supported conversions and their options, running "operations" (compress, merge, resize,
  extract, …), and downloading results.
license: MIT
metadata:
  product: api2convert
  api_version: "2.0.1"
  schema_url: https://api.api2convert.com/v2/schema
---

# api2convert REST API

api2convert is a hosted file-conversion API. You give it source files and one or more
**conversions**, it processes them asynchronously, and it returns downloadable **output**
files. It converts images, video, audio, documents, ebooks, archives, CAD, hashes and
metadata, and it also runs **operations** (compress, merge, resize, extract, OCR, website
capture, …).

This skill teaches you to drive that API end to end. When in doubt about an exact field,
target, or option, the **live OpenAPI schema is authoritative** — fetch
`GET https://api.api2convert.com/v2/schema`.

## Base URL

```
https://api.api2convert.com/v2/
```

HTTPS only. All request and response bodies are JSON (`Content-Type: application/json`),
except binary file uploads (multipart — see *Uploading files*).

## Authentication

Send your API key in the **`x-oc-api-key`** request header on every authenticated call:

```
x-oc-api-key: 0123456789abcdef0123456789abcdef
```

The key is a 32-character hex string. Get one from your api2convert account. The header name
is case-insensitive (`x-oc-api-key` is the canonical form).

- A small number of read-only endpoints need **no** key: `GET /statuses` and `GET /conversions`.
- Alternatively, a job can be addressed with its per-job **`x-oc-token`** (returned as `token`
  when the job is created) instead of the account key — useful for handing limited access to a
  single job to a client.

## Mental model

A **Job** is the unit of work. It holds:

- **input** — one or more source files (`InputFile`).
- **conversion** — one or more things to do (`Conversion`). Each conversion has a `target`
  (e.g. `png`, `mp3`, `pdf`) plus optional `category` and `options`.
- **output** — the resulting files (`OutputFile`), each with a download `uri`.

A job can contain several conversions, and each conversion can fan out to several outputs.

**Everything is a conversion.** A plain format conversion (`{"category":"audio","target":"mp3"}`)
and an "operation" (`{"category":"operation","target":"compress"}`) use the *exact same*
`Conversion` shape. There is no separate "operations" endpoint or field — see *Operations*.

A job moves through statuses (the `status.code` field): typically `incomplete` → `ready` →
`queued` → `downloading` → `processing` → `saving` → **`completed`** (or **`failed`**).

## The standard flow

1. **Create the job** with `POST /jobs`, including your input(s) and conversion(s). With
   `process: true` (the default) it starts as soon as all inputs are ready.
2. **Poll** `GET /jobs/{job_id}` until `status.code` is `completed` or `failed` — or set a
   `callback` URL and let api2convert notify you (see *Callbacks*).
3. **Download** each `output[].uri`.

### Minimal example (remote input, one-shot)

```bash
curl -X POST https://api.api2convert.com/v2/jobs \
  -H "x-oc-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": [
      { "type": "remote", "source": "https://example.com/photo.jpg" }
    ],
    "conversion": [
      { "category": "image", "target": "png" }
    ]
  }'
```

Response (abridged) — note the `id`, `token`, and `server`:

```json
{
  "id": "8daae6d1-26e0-11e5-b2a1-0800273b325b",
  "token": "12srxin63mgp23f8mtny2rgtgl1nl39i",
  "status": { "code": "downloading", "info": "..." },
  "server": "https://www2.api2convert.com/v2/dl/...",
  "conversion": [ ... ],
  "input": [ { "id": "...", "status": "downloading" } ]
}
```

### Poll and download

```bash
curl https://api.api2convert.com/v2/jobs/8daae6d1-26e0-11e5-b2a1-0800273b325b \
  -H "x-oc-api-key: $API_KEY"
```

When `status.code` is `completed`, read the outputs:

```json
{
  "status": { "code": "completed", "info": "..." },
  "output": [
    { "id": "...", "filename": "photo.png", "uri": "https://.../photo.png",
      "size": 102400, "content_type": "image/png", "status": "enabled" }
  ]
}
```

Treat both `server` and `output[].uri` as **opaque hosts** — always use the values the API
returns; never hardcode a download host.

## Uploading files

To convert local files, create the job **without an `input` field** (just the conversion), then
upload the bytes — the upload *creates* the input. The job starts as `incomplete` and processes
automatically once the file arrives.

1. Create the job with conversion(s) only. The response includes `id`, `token`, and the upload
   host **`server`**:

   ```json
   { "conversion": [ { "category": "image", "target": "jpg" } ] }
   ```

2. POST the file as multipart form-data (field name **`file`**) to
   `{server}/upload-file/{job_id}`:

   ```bash
   curl -X POST "{SERVER}/upload-file/{JOB_ID}" \
     -H "x-oc-api-key: $API_KEY" \
     -H "x-oc-upload-uuid: my-upload-1" \
     -F "file=@/path/to/photo.png"
   ```

   The `x-oc-upload-uuid` header identifies the upload (used for chunked / resumable transfers).
   On success it returns `200` and the job's `input[]` now lists the file (`type: "upload"`).

3. Poll `GET /jobs/{job_id}` until `completed`. To upload **several** files before starting,
   create the job with `process: false`, upload each file, then `PATCH {"process": true}`.

Input methods — set the input `type` when you *do* declare inputs in the body: `remote` (URL,
default), `upload` (created by the upload step above, not declared inline), `base64` (source is
the base64 string), `input_id` (reuse another input), `output` (chain a previous job's output
as new input), `cloud` and `gdrive_picker` (cloud storage; pass tokens via `credentials` /
location via `parameters`).

## Endpoint reference

All paths are relative to `https://api.api2convert.com/v2/`. "Auth" = requires `x-oc-api-key`.

| Method & path | Auth | Purpose |
|---|---|---|
| `POST /jobs` | yes | Create a job |
| `GET /jobs` | yes | List your active jobs (paginated, 50/page; `?status=`) |
| `GET /jobs/{job_id}` | yes | Get a job (status, inputs, outputs) |
| `PATCH /jobs/{job_id}` | yes | Modify a job / start it (`process: true`) |
| `DELETE /jobs/{job_id}` | yes | Cancel a job |
| `GET\|POST /jobs/{job_id}/conversions` | yes | List / add conversions |
| `GET\|PATCH\|DELETE /jobs/{job_id}/conversions/{id}` | yes | Read / modify / remove a conversion |
| `GET\|POST\|PATCH /jobs/{job_id}/input` | yes | List / add / patch inputs |
| `GET\|PATCH\|DELETE /jobs/{job_id}/input/{file_id}` | yes | Read / patch / delete an input |
| `GET /jobs/{job_id}/output` | yes | List outputs (`?conversion_id=` `?input_id=`) |
| `GET\|PATCH\|DELETE /jobs/{job_id}/output/{file_id}` | yes | Read / patch (rename, password) / delete an output |
| `GET /conversions` | no | Discover available conversions + options (`?category=` `?target=`) |
| `GET /statuses` | no | List all job status codes and descriptions |
| `GET /presets` … | yes | Saved option sets (list/create/update/delete) |
| `GET /contracts` | yes | Your active plan / limits |
| `GET /v2/schema` | no | The full OpenAPI (Swagger 2.0) schema |

## `POST /jobs` request body

Top-level fields (all field names are `snake_case`):

| Field | Type | Default | Notes |
|---|---|---|---|
| `conversion` | array | — | **Required.** One or more `Conversion` objects; each needs `target`. |
| `input` | array | — | Source files; omit and add later via the input endpoint or upload. |
| `process` | bool | `true` | Auto-start once inputs are ready. Set `false` to stage uploads first. |
| `fail_on_input_error` | bool | `true` | Fail the job if any input cannot be downloaded. |
| `fail_on_conversion_error` | bool | `true` | Fail the job if any conversion fails. |
| `notify_status` | bool | `false` | Fire the `callback` on every status change, not just the final one. |
| `callback` | string | — | Webhook URL for status updates. |
| `type` | string | `job` | Always `"job"`. |
| `limits` | object | — | Per-job overrides (`job` / `input` / `output`), bounded by your contract. |

A minimal body needs only `conversion`; the booleans have sensible defaults, so send them only
to change behavior.

**Conversion object** — `target` (required), `category`, `options` (target-specific), `metadata`
(e.g. `{"clear_all": true, "author": "..."}`), `output_target` (deliver results to S3, Google
Cloud, Azure, FTP, YouTube, or Google Drive).

**InputFile object** — `type` (see *Uploading files*), `source`, optional `filename`, `engine`
(`auto` | `video` | `file` | `website` | `screenshot` | `screenshot_pdf` | `zip`), `options`,
`credentials`, `parameters`.

## Discovering conversions and options

`GET /conversions` is the live catalogue of what the API can do and which options each target
accepts. **Query it instead of guessing or hardcoding** a target list:

```bash
curl "https://api.api2convert.com/v2/conversions?category=image&target=png"
```

Categories the API exposes: `image`, `video`, `audio`, `document`, `ebook`, `archive`, `cad`,
`hash`, `metadata`, and `operation`. Each returned entry includes `target`, `category`, and an
`options` schema describing the allowed parameters and values for that target.

## Operations ("Convert with Operation")

Beyond format-to-format conversion, api2convert offers **operations** — file actions that
aren't a simple "A → B" format change. An operation is just a conversion with
`category: "operation"` and an operation `target`, plus operation-specific `options`.

Publicly available operations include:

- **Image:** `compress`, `resize-image`, `thumbnail`, `compare-image`, `video-to-image`, `analyze-image`
- **Video / audio:** `cut-video`, `slideshow`, `merge-streams`, `extract-streams`,
  `compare-video`, `audio-volume`
- **PDF:** `convert-pdfa`, `validate-pdfa`, `pdf-booklet`, `compare-pdf`
- **Archive / assets:** `extract-archive`, `extract-assets`, `extract-assets-from-pdf`

> The authoritative, current list (with each operation's exact options) is
> `GET /conversions?category=operation`. Always confirm a target and its options there before
> relying on it.

### Operation examples

Compress an image:

```json
{
  "input": [ { "type": "remote", "source": "https://example.com/photo.jpg" } ],
  "conversion": [
    { "category": "operation", "target": "compress",
      "options": { "compression_level": "high", "compression_target": "jpg" } }
  ]
}
```

Cut a video into clips (produces multiple outputs):

```json
{
  "conversion": [
    { "category": "operation", "target": "cut-video",
      "options": {
        "cut_points": [
          { "start": "00:03:00.800", "end": "00:04:00.200" },
          { "start": "00:05:00.000", "end": "00:08:00.999" }
        ],
        "target_format": "mp4",
        "allow_multiple_outputs": true
      } }
  ]
}
```

Merge several streams (multiple inputs → one file). Operations like `merge-streams` and the
`compare-*` family take **more than one input**. Provide the inputs (here as remote URLs); where
an operation must address a specific input (e.g. channel mapping), reference it by the input
`id` returned in the create response:

```json
{
  "input": [
    { "type": "remote", "source": "https://example.com/left.wav" },
    { "type": "remote", "source": "https://example.com/right.wav" }
  ],
  "conversion": [
    { "category": "operation", "target": "merge-streams",
      "options": {
        "audio_channels": {
          "layout": "2.0",
          "front_left": "{input_file_id_1}",
          "front_right": "{input_file_id_2}"
        }
      } }
  ]
}
```

(Confirm the exact `merge-streams` options via
`GET /conversions?category=operation&target=merge-streams`.)

Extract the contents of an archive:

```json
{
  "input": [ { "type": "remote", "source": "https://example.com/files.zip" } ],
  "conversion": [
    { "category": "operation", "target": "extract-archive",
      "options": { "summary": true } }
  ]
}
```

## Response shapes

**Job** — `id`, `token`, `type`, `status` (`{code, info}`), `process`, `fail_on_input_error`,
`fail_on_conversion_error`, `notify_status`, `callback`, `server`, `spent` (credits used),
`created_at`, `modified_at`, plus arrays `conversion`, `input`, `output`, `errors`, `warnings`.

**InputFile** — `id`, `type`, `status` (`ready` | `downloading` | `failed` | `canceled`),
`source`, `filename`, `size`, `checksum`, `content_type`, `engine`, `options`, `metadata`.

**OutputFile** — `id`, `filename`, **`uri`** (download URL), `size`, `content_type`, `checksum`,
`status` (`enabled` | `disabled`), `downloads_counter`, `metadata`, `source`
(`{conversion, input[]}`).

**Conversion** — `id`, `target`, `category`, `options`, `metadata`, `output_target[]` (each with
a delivery `type` and a `status` of `waiting` | `uploading` | `completed` | `failed`).

## Callbacks (webhooks)

Set `callback` on the job to a URL you control. api2convert sends an HTTP `POST` with the Job
JSON to that URL:

- Default: a callback when the job reaches a **final** status (`completed` / `failed`).
- With `notify_status: true`: a callback on **every** status change.

Callbacks complement polling — use whichever fits your integration.

## Errors and failure handling

Two distinct error surfaces:

- **HTTP status** on the API call itself: `400` invalid input, `401` invalid credentials, `402`
  contract limit exceeded / payment required, `429` too many concurrent requests, `500` server
  error. The body is an `Error` (`{code, message, errors}`).
- **Per-job problems** while processing: the Job's `errors[]` and `warnings[]`. Each entry has
  `source` (`input` or `conversion`), `id_source`, `code`, `message`, `details`. A job can
  finish `completed` *with* warnings.

`fail_on_input_error` and `fail_on_conversion_error` (both default `true`) decide whether a
single bad input/conversion fails the whole job or is skipped while the rest proceed. To detect
success: confirm `status.code == "completed"` **and** check `errors[]`.

## Limits and contracts

Your plan governs file sizes, concurrency, retention and credits. Inspect it with
`GET /contracts`, and override per-job ceilings (within your plan) via the `limits` object.
Output files are retained for a limited time (typically a few weeks; failed jobs much shorter) —
treat retention as **contract-dependent** and download promptly. The job's `spent` field reports
credits consumed. Exact figures: see your contract and the official api2convert documentation.

## Tips for agents

- **Discover, don't hardcode.** Validate a `target` and its `options` via
  `GET /conversions?category=…&target=…` before submitting; for operations use
  `?category=operation`.
- **Prefer `process: true`** for one-shot remote-URL jobs; use `process: false` only when you
  must stage uploads first, then `PATCH {"process": true}`.
- **Poll with backoff** (e.g. 1s → 2s → 5s …) on `GET /jobs/{job_id}`, or use a `callback`.
- **Never hardcode hosts.** Upload to the job's `server`; download from `output[].uri`.
- **Respect limits.** Back off on `429`; surface `402` to the user (plan/credits).
- **The live `GET /v2/schema` wins.** If anything here differs from the schema, trust the
  schema.
