# api2convert > api2convert is a hosted REST API that converts, compresses, and transforms files — > images, video, audio, documents, ebooks, archives and CAD — and runs operations such as > compress, merge, resize, thumbnail, extract, OCR, PDF/A and website capture. You submit a > job with one or more conversions and input files; it processes asynchronously and returns > downloadable output files. Base URL: `https://api.api2convert.com/v2/` (HTTPS, JSON in and out). Authenticate with the `x-api2convert-api-key` request header. ## For AI agents - [api2convert API Agent Skill](https://www.api2convert.com/skills/api2convert-api/SKILL.md): A drop-in Agent Skill (SKILL.md) that teaches an AI agent how to authenticate and drive the api2convert REST API end to end — the job → input → conversion → output lifecycle, operations, polling, webhook callbacks, discovering supported conversions and their options, and downloading results. ## API reference - [OpenAPI schema](https://api.api2convert.com/v2/schema): Machine-readable Swagger 2.0 definition of every endpoint (authoritative source of truth). - [Available conversions and options](https://api.api2convert.com/v2/conversions): Live list of supported targets and operations with their option schemas (no auth required; filter with `?category=` and `?target=`). - [Job status codes](https://api.api2convert.com/v2/statuses): All job statuses and their descriptions (no auth required). ## Documentation - [Full documentation (single file)](https://www.api2convert.com/llms-full.txt): Every guide's complete text concatenated into one file (the llms-full.txt convention) — ingest this for the full docs in one fetch. - [API documentation](https://www.api2convert.com/documentation): Getting started and core concepts. - [API reference](https://www.api2convert.com/documentation/reference): Endpoint-by-endpoint reference. - [Supported file formats and operations](https://www.api2convert.com/documentation/formats): Everything you can convert and every "Convert with Operation" feature. - [Postman collection](https://www.api2convert.com/documentation/downloads#postman): Import the collection (or "Run in Postman") — a runnable Quickstart that chains a full create → upload → convert → poll → download flow, plus a request for every endpoint. ## Service status - [Status page](https://status.api2convert.com/): Live status page showing whether the API is operational, with 24h / 7d / 30d / 90d uptime and an incident history. Subscribe by email for outage and maintenance notifications. - [Service status guide](https://www.api2convert.com/documentation/guides/service-status): How to read the status page and what to do during an incident. ## Task API (`/v1`, on the `task.` host) The `/v2` API described above and the **Task API** are two different products. The Task API is the newer, `Authorization: Bearer` conversion API served on each brand's `task.` host, and its whole description — paths, parameters, credentials, error vocabulary and limits — is *generated* per brand on every request, so it cannot drift from the API that exists. - [Task API OpenAPI document](https://task.api2convert.com/openapi.json): Generated from the live operation catalogue and from the limits the fleet actually enforces — authoritative for everything below. YAML at `/openapi.yaml`. Anonymous: read it before you hold a credential. This index is served unchanged on every brand host, so if you fetched it from somewhere other than api2convert.com, read `https://task./openapi.json` instead — the paths and the credential model are identical, the operation catalogue is not. - **Error vocabulary:** the `x-sat-error-codes` extension at the root of the same document is the published `code` vocabulary, generated from the node's own error mapper rather than listed by hand. Each entry carries its HTTP `status` where it has one, a `description`, and `reserved` — `true` for a code published ahead of the release that first emits it. Branch on `code`, not on the status: one status can carry more than one code (`503` is both `SERVICE_UNAVAILABLE` and the storage-plane refusals — `STORAGE_BACKPRESSURE`, `STORAGE_UNAVAILABLE`, `STORAGE_CLUSTER_UNAVAILABLE`, `KEY_UNAVAILABLE`, `STORAGE_OBJECT_MISSING` — each with a `retryable` verdict and a `retry_after_seconds` base; the `Retry-After` header is jittered per response above that base). ### Published limits Generated rather than hand-maintained. They are the `x-sat-published-limits` extension at the root of that document, republished here so an agent does not need a second fetch, and stated exactly once each, in the form `` `key` = integer ``, so that `tests/Task/Contract/PublicationSurfacesAgreeTest.php` can fail the build the moment this file and the generated document disagree. **The document wins if they ever do.** One of the three is deliberately **not published as a number** — see the upload bullet. A figure missing here is missing there too, and the sweep above fails the build if this file states one the document does not. - `retention_seconds` = 86400 — seconds a stored file lives after it is written. Download it or re-run the app; there is no extension. - **Maximum request body: not published.** A body that is too large is refused with `413` and the code `PAYLOAD_TOO_LARGE`, in the same JSON envelope as every other error, and **the cap that actually applied is in `max_bytes` on that refusal** — read it from there rather than assuming one. Your plan may set a smaller cap, and a proxy in front of the node refuses before the node does at a limit that has not been measured; publishing a number before that measurement exists would promise a body size this API cannot be relied on to accept (`DEC-INFRA-10`). - `sync_run_ceiling_seconds` = 27 — seconds a synchronous `POST /run/…` waits for the app, counted from the moment the request arrives, before answering `408` `TASK_TIMEOUT` in the JSON envelope. This is the node's own wait-loop budget, and it sits strictly under the php-fpm pool's hard kill so that the `408` is written before the worker is killed; the task itself keeps running and can be read back with `GET /v1/task/{task_id}`. Use `POST /async/run/…` with a webhook for anything that may take longer, which is almost everything. Neither published number will be reduced without an RFC 9745 `Deprecation` header and a `Sunset` date announced at least one full release ahead. ## Data handling — retention, backups and where the bytes live Restated here from the privacy policy so an agent does not need a second fetch. No figure is repeated in the `key` = integer form used above: the published limits have exactly one home, and a second copy of a number is a number that will one day be wrong while looking right. - **Retention of Task-API files.** A stored file lives for the `retention_seconds` window published above and is then deleted. There is no extension; download it or re-run the app. - **A run can decline storage entirely.** `POST /v1/run/{operation}` takes a `store` flag. It defaults to `true` — the output is written to your storage, registered as a `file_type: output` file, and the run answers `302` with a signed, expiring download URL. Send `store=false` and the output is streamed back in the response body instead: nothing is written to storage, it never appears in `GET /v1/files`, it has no `file_id`, and there is nothing to delete afterwards or to expire. The flag is read from the JSON request body first and from the query string second; `StoreFile` is not accepted, in either place. The asynchronous form (`POST /async/run/…`) takes the same flag with the opposite default, because each side keeps the behaviour its existing callers integrated against. Billing for `store=false` runs is not documented in this contract yet; do not infer it from the parameter's existence. - **A file can ask to be kept: `persistence`.** `POST /v1/task/upload` (a form part beside the file, or a query parameter of the same name on a raw-body upload) and both run forms (JSON body first, query second) take `persistence`, one of `ephemeral` — the default: collected after the `retention_seconds` window — or `durable`: counts against your storage quota, is replicated to a storage cluster, and is kept until you delete it. `durable` is refused with `422 PERSISTENCE_NOT_AVAILABLE` on a service that does not offer durable storage yet; any other word is a `400`. `durable_sync` is a flag on `durable` (withhold the upload's answer until a cluster holds the file), never a persistence of its own. Every file record reads back the `persistence` that landed. - **Your quota is readable: `GET /v1/storage`.** Answers `{limit_bytes, used_bytes, pool, retention_policy: {ttl_seconds}}` for the authenticated account. `limit_bytes: null` means no quota (never 0); `pool: null` means no published placement; `retention_policy.ttl_seconds` is the same `retention_seconds` published above. An OAuth2 access token needs the `profile` scope; a `sec_` secret or task token is never scoped. Answered `Cache-Control: private, no-store`. - **Backups.** We make no backups of the files you transmit for conversion. Encrypted backups of our databases do exist and are kept for the limited period stated in the privacy policy. - **Location.** Data is stored in Europe; delivered through a global content delivery network. The object-storage processor is Cloudflare R2 (EU), whose buckets are created in the EU jurisdiction on its European endpoint and never on the provider's default endpoint. - **Output targets are outside all of the above.** A result delivered to an `output_target` you configure — S3, Google Cloud, Azure, FTP, Drive, YouTube — leaves our arrangement at the moment we hand it over. Its location and its retention are then yours. - [Privacy policy](https://www.api2convert.com/privacy): the full text of all of the above, including the rights that apply and how to exercise them.