---
title: "Start a media conversion job"
method: POST
path: "/api/convert/job"
tags: ["Convert"]
---

# Start a media conversion job

`POST /api/convert/job`

## Request

- Base URL: `https://snapwonders.com`
- URL: `https://snapwonders.com/api/convert/job`
- Auth: API key in header `X-Api-Key`

Submits conversion options and dispatches the job to the worker queue. All files must be fully uploaded via TUS and show `"status":"completed"` (verify with `GET /api/convert/session/{uid}/files`) before calling this endpoint.

The call is **idempotent**: calling it again for a session that already has a job returns the existing job without creating a duplicate.

**Authentication:** `X-Api-Key` header required.

## Request body

- object
  - `upload_uid` string, uuid, required: The `upload_uid` returned by `POST /api/convert/session`
  - `image_format` 'jpeg' | 'png' | 'webp' | 'avif' | 'heic' | 'jxl': Output format for image files. Default: `jpeg`.
  - `video_format` 'mp4h264' | 'mp4h265' | 'webm' | 'mkv' | 'mov': Output format for video files. Default: `mp4h264`.
  - `image_quality` integer: JPEG/WebP output quality 1–100. Default: 85.
  - `video_crf` integer: Video CRF value 0–51 (lower = better quality). Default: 23.
  - `video_max_dimension` 480 | 720 | 1080: Cap video resolution to this height in pixels. Omit or set to 0 to keep original resolution.
  - `strip_metadata` boolean: Strip EXIF/GPS/encoder metadata from output files. Default: `false`.
  - `image_resize_width` integer: Resize images to fit within this bounding-box width in pixels. Longest-edge fit, aspect ratio preserved, no upscaling. Omit for no resize.
  - `image_resize_height` integer: Resize images to fit within this bounding-box height in pixels. Longest-edge fit, aspect ratio preserved, no upscaling. Omit for no resize.
  - `pdf_dpi` integer: **PDF only.** Render resolution in DPI. Default: 150.
  - `pdf_page_from` integer: **PDF only.** First page to render, 1-based. Default: 1.
  - `pdf_page_to` integer: **PDF only.** Last page to render, 1-based. `0` means all pages. Default: 0.
  - `expiry` '1h' | '12h' | '1d' | '2d' | '1w' | '1m': How long the result download links remain accessible after the job completes. `1h` = 1 hour, `12h` = 12 hours, `1d` = 1 day (default), `2d` = 2 days, `1w` = 1 week, `1m` = 1 month. **Free-tier keys are silently clamped** to `upload.free_max_expiry` (default `1d`): the job still succeeds, but anything longer is reduced. Pro accounts get the requested value. No response currently returns the granted expiry, so assume the free maximum unless the owning account is Pro.

## Response `200`

Job already exists (idempotent repeat call) — returns existing job

## Other responses

- `201`: Job queued
- `400`: Validation error — no files uploaded, invalid option value, etc.
- `401`: Not authenticated. `error` names the exact cause: `missing_api_key`, `malformed_api_key`, `invalid_api_key` (key unknown/revoked/expired), or — when the key itself is valid — `account_not_verified` / `account_inactive`.
- `403`: Two distinct causes, named by `error`. `forbidden` — the session does not belong to your API key. `account_blocked` — an administrator has blocked this account from submitting jobs; permanent until reversed by support, so do not retry. `account_blocked` is a different axis from the 401 account-status codes: the account may be fully active and verified and still be job-blocked.
- `404`: Session not found
- `410`: Session expired — sessions are valid for 24 hours from creation
- `429`: Too many active jobs for this API key. Wait for queued/processing jobs to finish, then retry. Response includes `active_jobs` and `limit`.

---

[API](https://skmtc.dev/snapwonders/apis/snapwonders-api-mcp.md) · [All operations](https://skmtc.dev/snapwonders/apis/snapwonders-api-mcp/llms.txt) · [OpenAPI document](https://skmtc.dev/snapwonders/apis/snapwonders-api-mcp/revisions/645bbccc9550?raw)
