File conversion API

Convert files from your own code with the same converters as the website: an API key, a simple REST interface, credits and webhooks.

Quick start

Create a key on your account page, then send a file and the format you want:

curl -X POST https://api.101convert.com/v1/conversions \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@photo.jpg" \
  -F "target=webp" \
  -F "quality=85" \
  -F "wait=30"

The answer describes the conversion. With wait=30 a quick conversion is already finished in the same response; otherwise ask for its status later. Then download the result:

{
  "id": "cnv_01j9z3k8q4x7m2n5p6r8s9t0v1",
  "status": "succeeded",
  "source": "jpg",
  "target": "webp",
  "credits": 2,
  "result": {
    "filename": "photo.webp",
    "size": 48213,
    "download_url": "https://api.101convert.com/v1/conversions/cnv_01j9z3k8q4x7m2n5p6r8s9t0v1/download",
    "expires_at": "…"
  }
}

curl -o photo.webp -H "Authorization: Bearer $API_KEY" \
  https://api.101convert.com/v1/conversions/cnv_01j9z3k8q4x7m2n5p6r8s9t0v1/download

Authentication

Send your key in the Authorization header as "Bearer ". Keys are created and revoked on your account page and are shown only once. Keep them secret: anyone with your key can spend your credits.

Endpoints

Method Path Description
POST /v1/conversions Start a conversion from a file or a URL (also POST /v1/convert)
GET /v1/conversions/{id} Status of a conversion, with the result when it has finished
GET /v1/conversions/{id}/download Download the result, as many times as you need until it expires
DELETE /v1/conversions/{id} Cancel a conversion that is still waiting, or delete a result early
GET /v1/conversions Your conversions, newest first
GET /v1/formats All supported conversions
GET /v1/formats/{source} Targets of one source format with their options, variants, size limits and prices
GET /v1/account Your plan, remaining credits and limits

Input, options and formats

Send the file as the multipart field "file", or a public link as "url" (our servers download it). The source format is taken from the file name; send "source" if it has none. Options such as quality can be sent as plain fields (quality=85) or as options[quality]=85. GET /v1/formats/{source} lists every target with its options and limits.

curl -X POST https://api.101convert.com/v1/conversions \
  -H "Authorization: Bearer $API_KEY" \
  -d "url=https://example.com/report.docx" \
  -d "target=pdf"

curl -H "Authorization: Bearer $API_KEY" https://api.101convert.com/v1/formats/jpg

Waiting for the result

Conversions run in a queue. Ask GET /v1/conversions/{id} until the status is succeeded or failed, wait up to 30 seconds in the request itself with wait=30, or send a callback_url and we will call you. A result can be downloaded repeatedly for 24 hours.

Credits and limits

A conversion costs the same credits as on the website: the weight of the conversion type times the file size band, and only when it succeeds. Paid plans spend their monthly credits. A free account gets 100 free API credits every month.

Plan Credits per month Conversions at once Requests per minute
Free 100 free API credits 2 30
Lite 1,000 5 120
Standard 2,500 10 300
Pro 5,000 20 600

A 429 answer carries a Retry-After header. Conversions also count against your plan's limit of conversions per 10 minutes, which is shared with the website.

Compare plans

Webhooks

With a callback_url (https only) we send a POST with the conversion as JSON when it finishes. Check the X-101convert-Signature header: it holds t, a Unix time, and v1, the HMAC-SHA256 of "t.body" made with the webhook secret from your account page. Reject old timestamps to stop replays. Failed deliveries are retried for about an hour and a half.

// PHP
[$t, $v1] = array_map(fn ($p) => explode('=', $p, 2)[1],
    explode(',', $_SERVER['HTTP_X_101CONVERT_SIGNATURE']));
$body  = file_get_contents('php://input');
$valid = abs(time() - (int) $t) < 300
    && hash_equals(hash_hmac('sha256', "$t.$body", $webhookSecret), $v1);

// Node.js
const [t, v1] = req.headers['x-101convert-signature'].split(',').map(p => p.split('=')[1]);
const expected = crypto.createHmac('sha256', webhookSecret).update(`${t}.${rawBody}`).digest('hex');
const valid = Math.abs(Date.now() / 1000 - t) < 300
    && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));

Safe retries

Send an Idempotency-Key header with a unique value of your own. If the request is repeated, for example after a timeout, you get the original conversion back instead of a new one, and you pay only once.

curl -X POST https://api.101convert.com/v1/conversions \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: invoice-2026-0042" \
  -F "file=@invoice.docx" -F "target=pdf"

Errors

Every error has the same shape. Branch on code, which never changes; message is for people and follows the Accept-Language header.

{
  "error": {
    "code": "file_too_large",
    "message": "…",
    "details": { "max_upload_mb": 60 }
  }
}
Code HTTP Meaning
unauthenticated 401 Missing or invalid API key. Send it as "Authorization: Bearer <key>".
forbidden 403 This API key is not allowed to do that.
validation_failed 422 Some request parameters are missing or invalid.
unsupported_conversion 422 Converting A to B is not supported.
file_too_large 413 File is too large. Maximum size is N MB.
insufficient_credits 402 Not enough credits: this conversion costs N, your balance is N.
free_quota_exhausted 402 The free monthly API allowance is used up (N of N credits left, this conversion costs N). Upgrade to a paid plan to continue.
rate_limited 429 Too many requests. Wait for the time in the Retry-After header and try again.
concurrency_limit 429 Too many conversions in progress (your plan allows N at once). Wait for some to finish.
idempotency_conflict 409 This Idempotency-Key was already used for a different request.
not_ready 409 The conversion has not finished successfully, so there is nothing to download.
expired 410 The result has expired and was deleted. Convert the file again.
api_disabled 503 The API is temporarily unavailable. Please try again later.

Examples

# Python
import requests, time

API = "https://api.101convert.com/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}

with open("interview.mp3", "rb") as f:
    c = requests.post(f"{API}/conversions", headers=headers,
                      files={"file": f}, data={"target": "docx"}).json()

while c["status"] not in ("succeeded", "failed"):
    time.sleep(5)
    c = requests.get(c["links"]["self"], headers=headers).json()

if c["status"] == "succeeded":
    open("interview.docx", "wb").write(
        requests.get(c["result"]["download_url"], headers=headers).content)
// PHP (Laravel)
$c = Http::withToken($apiKey)
    ->attach('file', fopen('slides.pptx', 'r'), 'slides.pptx')
    ->post('https://api.101convert.com/v1/conversions', ['target' => 'pdf', 'wait' => 30])
    ->json();

if ($c['status'] === 'succeeded') {
    file_put_contents('slides.pdf', Http::withToken($apiKey)->get($c['result']['download_url'])->body());
}
// JavaScript (Node 18+)
const form = new FormData();
form.append('file', new Blob([await fs.promises.readFile('scan.png')]), 'scan.png');
form.append('target', 'pdf');
form.append('callback_url', 'https://example.com/hooks/101convert');

const res = await fetch('https://api.101convert.com/v1/conversions', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
  body: form,
});
const conversion = await res.json(); // status "queued"; the webhook follows