Quickstart
Get a free API key, convert a Word file to PDF with curl, Python or Node.js, and read the JSON that comes back.
You send a file to POST /v2/convert/{from}/to/{to} as a multipart form, and the converted file comes back base64-encoded in a JSON response. This page takes you from no key to a PDF on disk in three steps.
1. Get an API key
Sign in with Google or GitHub at app.pdfconversionapi.com, and you get a free key on the Free plan: 250 conversions a month, files up to 10 MB and 1 conversion at a time. The key is shown once, so copy it before you leave the page. Authentication covers replacing it and checking your usage.
Keep the key out of your source code and out of anything that runs in a browser. Every example on this site reads it from the PDFCONVERSIONAPI_KEY environment variable:
export PDFCONVERSIONAPI_KEY="paste-your-key-here"2. Convert a file
You need a Word file named report.docx in the current folder. If you don't have one, download our test document (26 KB, 3 pages) and save it under that name.
The base URL is https://api.pdfconversionapi.com. Pick your language:
# Needs curl, jq and base64.
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/docx/to/pdf \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@report.docx \
-o response.json
jq -r '.Files[0].FileData' response.json | base64 --decode > report.pdf# Needs the requests package: pip install requests
import base64
import os
import requests
with open("report.docx", "rb") as f:
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/docx/to/pdf",
headers={"Authorization": f"Bearer {os.environ['PDFCONVERSIONAPI_KEY']}"},
files={"File": f},
timeout=240,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
for file in result["Files"]:
with open(file["FileName"], "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(file["FileName"], file["FileSize"], "bytes")// Needs Node.js 20 or later (built-in fetch, FormData and Blob).
// Save it as convert.mjs and run: node convert.mjs
import { readFile, writeFile } from "node:fs/promises";
const form = new FormData();
form.append("File", new Blob([await readFile("report.docx")]), "report.docx");
const response = await fetch("https://api.pdfconversionapi.com/v2/convert/docx/to/pdf", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PDFCONVERSIONAPI_KEY}` },
body: form,
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.Code}: ${result.Message}`);
for (const file of result.Files) {
await writeFile(file.FileName, Buffer.from(file.FileData, "base64"));
console.log(file.FileName, file.FileSize, "bytes");
}We ran all three on 2026-11-03 against the API server running locally in a container, built the same way as the hosted service, with only the base URL changed. Versions: curl 8.7.1, jq 1.8.1, Python 3.14.2 with requests 2.34.2, Node.js 24.15.0. Each one wrote a 3-page report.pdf of 82,830 bytes.
3. Read the response
A successful conversion returns HTTP 200 and this JSON. It is the response from our test run, with FileData shortened:
{
"ConversionCost": 1,
"ConversionTime": 0.066,
"Files": [
{
"FileName": "report.pdf",
"FileExt": "pdf",
"FileSize": 82830,
"FileData": "JVBERi0xLjcKJYCAgIAKMSAwIG9iago8PC9UeXBl..."
}
]
}Fileshas one entry per output file. A one-page-per-image conversion, such as PDF to JPG, returns several.FileDatais the file itself, base64-encoded.FileSizeis its size in bytes after decoding.ConversionTimeis how many seconds the conversion took on our side, without upload and download time.ConversionCostis always 1. One request is one conversion, however many pages or files it returns. Only successful conversions count toward your plan's month.
Responses covers every field and how several output files are named.
When a request fails, the status is 4xx or 5xx and the body is a JSON error. This is what a missing or wrong key returns:
{"Code":401,"Message":"a valid API key is required (Authorization: Bearer <key>)"}The curl version doesn't check the status, so on an error response.json holds this message instead of a file. The Python and Node.js versions stop and print it.
Two errors don't have a JSON body: a request body that isn't a multipart form gets a plain-text 400, and the edge network in front of our API can refuse a request over 100 MB with its own 413 response. Errors and retries covers both.
Next steps
- Sending files and parameters: several files at once, page ranges, resolution, output names.
- Errors and retries: what each status code means and which ones to retry.
- Download links instead of base64: set
StoreFile=trueto get a link that works for 3 hours. - Limits: your plan's conversions a month, upload size and conversions at once, plus 120 seconds per conversion and 600 requests a minute.
- The list of all 556 conversions, or the same list from the API with
GET /v2/info.