# API reference

> Endpoints, parameters and response objects for the Converterrr REST API: formats, uploads, jobs and account.

URL: https://www.converterrr.com/developers/reference

All endpoints live under `https://www.converterrr.com/api/v1` and return JSON. Authenticate with `Authorization: Bearer <key>` (or `x-api-key: <key>`). Machine-readable spec: https://www.converterrr.com/api/v1/openapi.json. Guide, errors and limits: https://www.converterrr.com/developers.md.

## Endpoints

| Method | Path | Description | Auth |
| --- | --- | --- | --- |
| GET | `/formats` | List formats and conversions | None |
| POST | `/uploads` | Create a presigned upload | API key |
| GET | `/jobs` | List jobs | API key |
| POST | `/jobs` | Create a conversion or compression job | API key |
| GET | `/jobs/{id}` | Retrieve a job | API key |
| DELETE | `/jobs/{id}` | Cancel a queued job or delete its files early | API key |
| GET | `/account` | Credits and limits for the API key's account | API key |

## List formats: GET /formats

Every supported format and every conversion available through the API (conversions with a cloud route). No authentication required. Filter with `?from=png`.

```bash
curl "https://www.converterrr.com/api/v1/formats?from=heic"
```

```json
{
  "object": "list",
  "formats": [{ "id": "heic", "name": "HEIC", "title": "High Efficiency Image Container", "category": "image", "mime": "image/heic", "extensions": ["heic"] }, …],
  "conversions": [{ "from": "heic", "to": "jpg", "engine": "imagemagick" }, …]
}
```

## Create an upload: POST /uploads

Returns a presigned URL and its `expires_at`. `PUT` the raw file bytes to it, then pass the returned `id` as `input.upload_id` when creating a job. `max_size` is your plan's file-size limit in bytes.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `filename` | string | Yes | File name including extension, used to detect the input format. |

```json
{
  "object": "upload",
  "id": "upl_dXBsb2Fkcy9hcGkv…",
  "filename": "interview.mov",
  "upload_url": "https://blob.vercel-storage.com/?pathname=…&vercel-blob-signature=…",
  "method": "PUT",
  "max_size": 1073741824,
  "expires_at": "2026-11-05T15:02:11.204Z"
}
```

## Create a job: POST /jobs

Starts a conversion, or a compression with `operation: "compress"` (same format in, smaller file out). Send JSON with an input URL or upload id, or `multipart/form-data` with a `file` field for small files (`options` is then a JSON-encoded string).

| Parameter | Type | Description |
| --- | --- | --- |
| `input.url` | string | Public http(s) URL to download the file from. |
| `input.filename` | string | Override the file name (and detected format) for URL inputs. |
| `input.upload_id` | string | An id returned by `POST /uploads`. |
| `input_format` | string | Format id of the input. Detected from the file name when omitted. |
| `output_format` | string | Format id to convert to, e.g. `pdf`, `mp4`, `webp`. Required unless `operation` is `compress`. |
| `operation` | string | `convert` (default) or `compress`. |
| `compression_level` | string | `light`, `balanced`, `strong`; default `balanced`. Compression only. |
| `target_size` | integer or string | Compress to at most this size: bytes, or "500kb" / "2mb" (decimal units). Overrides the level; lossless formats (archives, FLAC) can't hit a target. |
| `options.quality` | integer | 1–100. Lossy images and video. |
| `options.width` / `options.height` | integer | Resize, keeping the aspect ratio when only one is given. |
| `options.keep_metadata` | boolean | Keep EXIF/ID3 and other metadata. Default true. |
| `options.video_bitrate_kbps` | integer | Target video bitrate. |
| `options.audio_bitrate_kbps` | integer | Target audio bitrate. |
| `options.sample_rate` | integer | Audio sample rate in Hz. |
| `options.fps` | integer | Output frame rate (video, GIF). |
| `options.dpi` | integer | Render resolution for PDF/vector to image (72–600). |
| `webhook_url` | string | Receives a POST when the job finishes or fails. |

```bash
curl https://www.converterrr.com/api/v1/jobs \
  -H "Authorization: Bearer $KEY" \
  -F file=@photo.heic \
  -F output_format=jpg \
  -F 'options={"quality": 90}'
```

Returns `201` with a job object in the `queued` state. Compression jobs have `operation: "compress"` and a `compression` object.

## Retrieve a job: GET /jobs/:id

Poll every 1–2 seconds until `status` is `completed` or `failed`, or use a webhook instead.

Statuses: `queued`, `processing`, `completed`, `failed`, `cancelled`, `expired`.

```json
{
  "id": "cm3x9q2f80001",
  "object": "job",
  "status": "completed",
  "source": "api",
  "operation": "convert",
  "compression": null,
  "conversion": { "from": "docx", "to": "pdf", "label": "DOCX → PDF" },
  "engine": "libreoffice",
  "input": { "name": "q3-report.docx", "size": 812331 },
  "output": {
    "name": "q3-report.pdf",
    "size": 401227,
    "url": "https://…blob.vercel-storage.com/outputs/…/q3-report.pdf",
    "download_url": "https://…blob.vercel-storage.com/outputs/…/q3-report.pdf?download=1"
  },
  "credits": 2,
  "error": null,
  "created_at": "2026-11-05T14:02:11.204Z",
  "started_at": "2026-11-05T14:02:11.950Z",
  "completed_at": "2026-11-05T14:02:15.318Z",
  "expires_at": "2026-11-06T14:02:15.318Z",
  "duration_ms": 3368
}
```

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string |  |
| `object` | `job` |  |
| `status` | `queued`, `processing`, `completed`, `failed`, `cancelled`, `expired` |  |
| `source` | `web`, `api` |  |
| `operation` | `convert`, `compress` |  |
| `compression` | object or null | Set for compression jobs. Fields: `level`, `target_bytes` |
| `conversion` | object | Fields: `from`, `to`, `label` |
| `engine` | string or null |  |
| `input` | object | Fields: `name`, `size` |
| `output` | object or null | Fields: `name`, `size`, `url`, `download_url` |
| `credits` | integer |  |
| `error` | string or null |  |
| `created_at` | string (date-time) |  |
| `started_at` | string (date-time) or null |  |
| `completed_at` | string (date-time) or null |  |
| `expires_at` | string (date-time) or null |  |
| `duration_ms` | integer or null |  |

## List jobs: GET /jobs

| Parameter | Type | Description |
| --- | --- | --- |
| `limit` | integer | 1–100, default 25. |
| `starting_after` | string | Job id to paginate after (the previous page's last item). |
| `status` | string | Filter by status. |

```json
{ "object": "list", "data": [ { "id": "cm3x9q2f80001", "object": "job", … } ], "has_more": false }
```

## Cancel or delete a job: DELETE /jobs/:id

Cancels a `queued` job (credits are refunded) or schedules a finished job's files for immediate deletion. Jobs that are already `processing` return `409 in_progress`.

## Account: GET /account

Plan, credits and limits for the account that owns the API key.

```json
{
  "object": "account",
  "plan": "…",
  "credits": { "balance": …, "subscription": …, "packages": …, "daily_free_used": …, "daily_free_limit": … },
  "limits": { "max_file_size_mb": …, "concurrency": … }
}
```

## Errors

| Status | Code | Meaning |
| --- | --- | --- |
| 400 | `invalid_request` | The body or parameters are invalid. The message names the field. |
| 400 | `invalid_url` | `input.url` isn't a public http(s) URL. |
| 400 | `unsupported_format` | Unknown format or file extension; pass `input_format` if it can't be detected. |
| 400 | `unsupported_conversion` | The pair has no cloud route (some conversions only run in the browser). |
| 400 | `unsupported_compression` | The format can't be compressed in the cloud. |
| 400 | `missing_output_format` | `output_format` is required for conversions. |
| 400 | `invalid_target_size` | target_size must be bytes or a size like "500kb" or "2mb". |
| 401 | `unauthorized` | Missing, invalid or revoked API key. |
| 402 | `plan_required` | The account has no active paid plan. The API is included in every paid plan. |
| 402 | `insufficient_credits` | Not enough credits for this job. |
| 403 | `email_unverified` | Verify your email address to use the API. |
| 404 | `not_found` | The job or upload doesn't exist (or isn't yours). |
| 409 | `upload_incomplete` | The presigned upload hasn't finished; PUT the file to `upload_url` first. |
| 409 | `in_progress` | `DELETE /jobs/:id` on a job that is already processing. |
| 413 | `file_too_large` | The file is larger than your plan allows. |
| 429 | `rate_limited` | Too many requests for this API key. Back off and retry. |
| 500 | `internal_error` | Something went wrong on our side. |
| 503 | `cloud_unavailable` | Cloud conversion is temporarily unavailable. |
