FileConvertsFree online file converter

File Converts API

A simple REST API for server-side conversions (PDF↔Office, table extraction, and more). Authenticate with an API key, create a job, stream progress, and download the result — or receive a signed webhook when it's done.

Authentication

Create a key in your account dashboard, then send it as an X-API-Key header. Call the API only from a server you control: an API key in browser JavaScript is readable by anyone who opens the page. If your users need to convert files in the browser, use the in-browser tools \u2014 those upload nothing and need no key at all. Keys are shown once — store them securely. The base URL is https://filetransmute-api.fly.dev.

Quickstart

cURL

# 1. Create a job (authenticate with your API key)
curl -X POST https://filetransmute-api.fly.dev/v1/jobs \
  -H "X-API-Key: ak_live_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "tool=pdf-to-excel" \
  -F "file=@invoice.pdf"
# → { "id": "job_…", "status": "queued", "events_url": "/v1/jobs/job_…/events" }

# 2. Poll status until "done" (or "failed"), then download.
#    Jobs created with a key belong to your org: send the key on every call.
curl https://filetransmute-api.fly.dev/v1/jobs/job_… -H "X-API-Key: ak_live_…"
curl -o out.xlsx https://filetransmute-api.fly.dev/v1/jobs/job_…/download -H "X-API-Key: ak_live_…"

JavaScript (Node)

// Node 18+ — run this on your server, never in browser code.
import { readFile, writeFile } from "node:fs/promises";

const auth = { "X-API-Key": process.env.FILE_CONVERTS_API_KEY };
const form = new FormData();
form.append("tool", "pdf-to-excel");
form.append("file", new Blob([await readFile("invoice.pdf")]), "invoice.pdf");

const res = await fetch("https://filetransmute-api.fly.dev/v1/jobs", {
  method: "POST",
  headers: { ...auth, "Idempotency-Key": crypto.randomUUID() },   // safe to retry
  body: form,
});
if (!res.ok) throw new Error(`create failed: ${res.status} ${await res.text()}`);
const { id } = await res.json();

// Poll until the job finishes (or register a webhook instead).
let job;
do {
  await new Promise((r) => setTimeout(r, 500));
  job = await (await fetch(`https://filetransmute-api.fly.dev/v1/jobs/${id}`, { headers: auth })).json();
} while (job.status === "queued" || job.status === "running");
if (job.status !== "done") throw new Error(job.error ?? "conversion failed");

const out = await fetch(`https://filetransmute-api.fly.dev/v1/jobs/${id}/download`, { headers: auth });
await writeFile(job.output_name, Buffer.from(await out.arrayBuffer()));

Python

import os, time, uuid, requests

auth = {"X-API-Key": os.environ["FILE_CONVERTS_API_KEY"]}
with open("invoice.pdf", "rb") as f:
    r = requests.post("https://filetransmute-api.fly.dev/v1/jobs",
                      headers={**auth, "Idempotency-Key": str(uuid.uuid4())},
                      data={"tool": "pdf-to-excel"}, files={"file": f})
r.raise_for_status()
job_id = r.json()["id"]

# Poll until done. The key goes on every call: the job belongs to your org.
while True:
    s = requests.get(f"https://filetransmute-api.fly.dev/v1/jobs/{job_id}", headers=auth).json()
    if s["status"] in ("done", "failed"):
        break
    time.sleep(0.5)
if s["status"] == "failed":
    raise RuntimeError(s["error"])

out = requests.get(f"https://filetransmute-api.fly.dev/v1/jobs/{job_id}/download", headers=auth)
out.raise_for_status()
open(s["output_name"], "wb").write(out.content)

Endpoints

POST/v1/jobsCreate a conversion job (multipart: file, tool). Supports Idempotency-Key.
GET/v1/jobs/{id}Job status, progress, and output name.
GET/v1/jobs/{id}/eventsServer-Sent Events stream of live progress.
GET/v1/jobs/{id}/downloadDownload the finished file.
GET/v1/formatsSupported server tools and which are available.
GET/v1/usageYour org's jobs, bytes processed, and credits spent.
GET/v1/api-keysList your API keys.
POST/v1/api-keysCreate a key (secret shown once).
GET/v1/webhooksList webhook endpoints.
POST/v1/webhooksRegister a webhook (signing secret shown once).

Idempotency

Pass an Idempotency-Key header on POST /v1/jobs. A retry with the same key returns the original job (and never charges twice) — safe for network retries.

Webhooks

Register an endpoint at POST /v1/webhooks to receive job.completed and job.failed events. Each delivery is signed with your webhook secret in the X-FileTransmute-Signature header — verify it before trusting the payload:

import hmac, hashlib
# Python. Header: X-FileTransmute-Signature: sha256=<hex HMAC-SHA256 of the raw body>
# Use the raw request bytes — re-serialising parsed JSON changes them.
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-FileTransmute-Signature", "")):
    abort(401)

Rate limits

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. When exceeded you get 429 with a Retry-After header.

Full interactive reference (OpenAPI / Swagger) is served at https://filetransmute-api.fly.dev/docs.