Responses
A successful conversion returns every output file in one JSON body, base64-encoded: nothing to poll and nothing to fetch afterwards.
Contents (7 sections)
The status is HTTP 200 and the body is JSON. The one exception to getting the data itself is StoreFile=true, which returns a download link in its place (Stored files).
The response body
This is the response to pdf/to/jpg for a two-page PDF at 72 DPI, from our test run, with FileData shortened:
{
"ConversionCost": 1,
"ConversionTime": 0.036,
"Files": [
{
"FileName": "season-guide-1.jpg",
"FileExt": "jpg",
"FileSize": 65272,
"FileData": "/9j/4AAQSkZJRgABAgEASABIAAD/wAARCAMYAmQD..."
},
{
"FileName": "season-guide-2.jpg",
"FileExt": "jpg",
"FileSize": 66627,
"FileData": "/9j/4AAQSkZJRgABAgEASABIAAD/wAARCAMYAmQD..."
}
]
}| Field | Type | What it holds |
|---|---|---|
ConversionCost | integer | Always 1. One request is one conversion, however many pages or files come back. |
ConversionTime | number | Seconds the conversion took on our side, rounded to the millisecond. The clock starts when a conversion slot picks up your request, so it leaves out your upload, any wait for a free slot, and the transfer of the response. |
Files | array | One entry per output file. A 200 response always has at least one. |
Files[].FileName | string | The output's name, extension included. See how outputs are named. |
Files[].FileExt | string | The extension in lower case, without the dot: pdf, jpg, xlsx. |
Files[].FileSize | integer | The file's size in bytes, after decoding. |
Files[].FileData | string | The file itself, base64-encoded with the standard alphabet and = padding, on one line. Left out when you send StoreFile=true. |
Files[].Url | string | Only with StoreFile=true: a link to the file that works for 3 hours. See Stored files. |
Files[].FileId | string | Only with StoreFile=true: the stored file's id, 32 hex characters. You need it to delete the file early. |
Field names are case-sensitive in JSON: read Files, not files. There is no MIME type field. If you need one, map it from FileExt.
ConversionTime helps you separate our processing time from network time. If a request takes 3 seconds on your side and ConversionTime is 0.4, the rest went to the upload, the download and waiting.
Response headers
A conversion response carries these headers from the API:
| Header | Value |
|---|---|
Content-Type | application/json |
x-request-id | A random id for this request. Log it with your own record of the call; Errors explains when to send it to us. |
X-Content-Type-Options | nosniff |
Retry-After appears only on 429 and 503 errors.
Several output files
Some conversions return one file per page, per part or per archive entry. Files then has several entries, in a fixed order:
| Conversion | What comes back | Names |
|---|---|---|
| PDF to JPG, PNG, WebP or SVG | One file per page | season-guide-1.jpg, season-guide-2.jpg |
| Word, PowerPoint, spreadsheet, email and e-book files to JPG, PNG or WebP | One file per page | report-1.png, report-2.png, report-3.png |
pdf/to/split | One PDF per part | statements-1.pdf, statements-2.pdf |
pdf/to/extract-images | One file per image | season-guide-image-1.png, season-guide-image-2.png |
zip/to/extract | One file per file in the archive | The entry's own name without its folders. A name that repeats gets -2, -3: notes.txt, notes-2.txt. |
The numbers mean different things:
- Page images are numbered by their page in the source document. With
PageRange=2-3you get-2and-3, not-1and-2. A single page still gets its number: page 2 alone comes back asseason-guide-2.jpg. - Split parts are counted from 1, whatever pages they hold.
TIFF output works differently. From PDF, DOC, DOCX, XLS, XLSX, PowerPoint (PPT, PPTX, PPS, PPSX, POTX), Visio, Publisher, email and e-book files, several pages come back as one multi-page TIFF by default (report.tiff), while a single page keeps its page number (report-1.tiff). Send MultiPage=false for one TIFF per page, named like the other page images. From the other document formats (OpenDocument, RTF, TXT, CSV, WordPerfect, XLSB, DOT, DOTX and XLTX), TIFF output is one file per page by default; send MultiPage=true to get one multi-page TIFF instead.
This renders pages 2 and 3 of a six-page PDF (our sample, saved as statements.pdf) and lists what came back:
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@statements.pdf \
-F PageRange=2-3 \
-F ImageResolution=72 \
-o response.json
jq -c '.Files[] | {FileName, FileExt, FileSize}' response.json{"FileName":"statements-2.jpg","FileExt":"jpg","FileSize":45411}
{"FileName":"statements-3.jpg","FileExt":"jpg","FileSize":48164}Choose the output name: FileName
Without FileName, the output takes the name of the file you uploaded, with the new extension: report.docx comes back as report.pdf. When a conversion takes several files, such as pdf/to/merge, the first file's name is used.
Send FileName to set the name yourself:
- Leave out the extension. We add the right one. Everything from the last dot onward is treated as an extension and dropped, so
FileName=report.v2givesreport.pdf. - Allowed characters are letters (accented ones too), digits, spaces,
-,_and.. Anything else becomes_:Q3 report (final)givesQ3 report _final_.pdf. - Dots and spaces at the start and end are removed, and the name is cut at 120 characters.
- If nothing is left after cleaning, the uploaded file's name is used instead.
- With several outputs,
FileNamereplaces the part before the number, and the numbering stays. - Unpacked files keep their own names.
zip/to/extractandpdf/to/extract-attachmentsname each output after the file stored in the input, andFileNamedoesn't change them.
Output names never contain a slash or a backslash.
This is the request above with a name of our choosing:
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@statements.pdf \
-F PageRange=2-3 \
-F ImageResolution=72 \
-F FileName=march \
-o response.json
jq -r '.Files[].FileName' response.jsonmarch-2.jpg
march-3.jpgDecode FileData
Each example below converts a two-page PDF to one JPG per page and writes every file in Files to disk. To follow along, download our sample PDF (118 KB, 2 pages) and save it as season-guide.pdf.
The whole response sits in memory while you decode it, and base64 is a third larger than the file it encodes: a 60 MB result arrives as about 80 MB of JSON.
#!/bin/sh
# Needs curl 7.76 or later (for --fail-with-body), jq and base64.
# Save it as decode.sh and run: sh decode.sh
set -eu
curl -sS --fail-with-body -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@season-guide.pdf \
-F ImageResolution=72 \
-o response.json
count=$(jq '.Files | length' response.json)
i=0
while [ "$i" -lt "$count" ]; do
name=$(jq -r ".Files[$i].FileName" response.json)
jq -r ".Files[$i].FileData" response.json | base64 --decode > "$name"
echo "wrote $name"
i=$((i + 1))
done# Needs the requests package: pip install requests
import base64
import os
import requests
with open("season-guide.pdf", "rb") as f:
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg",
headers={"Authorization": f"Bearer {os.environ['PDFCONVERSIONAPI_KEY']}"},
files={"File": f},
data={"ImageResolution": "72"},
timeout=240,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("pages", exist_ok=True)
for file in result["Files"]:
data = base64.b64decode(file["FileData"], validate=True)
if len(data) != file["FileSize"]:
raise SystemExit(f"{file['FileName']}: expected {file['FileSize']} bytes, got {len(data)}")
with open(os.path.join("pages", file["FileName"]), "wb") as out:
out.write(data)
print(file["FileName"], file["FileSize"], "bytes")// Needs Node.js 20 or later. Save it as decode.mjs and run: node decode.mjs
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
form.append("File", new Blob([await readFile("season-guide.pdf")]), "season-guide.pdf");
form.append("ImageResolution", "72");
const response = await fetch("https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg", {
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}`);
await mkdir("pages", { recursive: true });
for (const file of result.Files) {
const data = Buffer.from(file.FileData, "base64");
if (data.length !== file.FileSize) {
throw new Error(`${file.FileName}: expected ${file.FileSize} bytes, got ${data.length}`);
}
await writeFile(join("pages", file.FileName), data);
console.log(file.FileName, file.FileSize, "bytes");
}In the curl version, an error makes curl exit with code 22, which stops the script, and response.json holds the error instead of files. The Python and Node.js versions print:
season-guide-1.jpg 65272 bytes
season-guide-2.jpg 66627 bytesWe ran all three on 2026-11-04 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.
Links instead of FileData
With StoreFile=true, each entry in Files has Url and FileId in place of FileData, and the rest of the response is the same. Stored files covers how long the link works and how to delete the file early.
When the request fails
Any status other than 200 means no files. The body is a JSON error with the status in Code and the reason in Message:
{"Code":400,"Message":"PageRange is not supported yet for DOCX → PDF"}Errors lists every status, the few responses that aren't JSON, and which ones to retry.