Skip to content
pdfconversionapi

API design6 min read

Why our API refuses options it doesn't support

Set a documented option to a value our converter can't apply and you get a 400 that names it, not a file. How the check works, where it stops, three real responses, and what your client should do.

Written and tested by Zeel Shekhaliya, Founder

Contents (5 sections)

If you set a documented option to a value our converter can't apply, the API answers 400 and names the option instead of returning a file. A file that ignored part of your request looks fine until someone opens it, and by then it may already be in a customer's inbox.

Shell
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@season-guide.pdf \
  -F BitDepth=8
Output
{"Code":400,"Message":"BitDepth is not supported yet for PDF → JPG"}

Where the list of options comes from

We use ConvertAPI's parameter names. We compiled its documented options for each conversion, with their default values, into a JSON file that is built into the API. It covers 313 of our 556 conversions and 2,213 options between them. The 313 include conversions such as DOC to PDF that ConvertAPI handles on another endpoint (its docx/to/pdf also takes DOC files).

The main check doesn't rely on a hand-written list of which options each converter supports. Every parameter lookup goes through one shared type, and it records each name a converter asks for, whether or not the request contained it. Names are compared in lowercase, so bitdepth and BitDepth are the same option. When one converter hands its parameters to another, both share the record.

After the converter finishes, the registry looks at every option the request sent. The request fails with 400 when an option is:

  • documented by ConvertAPI for this conversion,
  • set to something other than its documented default, and
  • never looked up by the code that ran.

This check compares the default loosely: true, 1, yes and on are the same value, 75.0 equals 75, text ignores letter case, and an empty value counts as not sent. An option that has no effect on a conversion by design has to be declared in code. The email converter marks IgnoreAttachmentErrors and Merge as handled, because it lists attachments and never converts them.

A file uploaded under a documented option name is refused if nothing reads it, whatever it contains. Building the check turned up a bug of exactly this kind in our own code, before launch. The email converter looked for an uploaded TemplateFile under its mixed-case name, but field names are stored in lowercase, so the template was dropped and the email was converted without it. That field now returns 400 until we support templates.

Three requests and what came back

One option the converter never reads

The request at the top of this page sets BitDepth=8 on PDF to JPG, and our PDF to JPG converter never reads that option. Send the documented default instead and the conversion goes through:

Shell
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@season-guide.pdf \
  -F BitDepth=default \
  -o response.json

jq -c '.Files[] | {FileName, FileSize}' response.json
Output
{"FileName":"season-guide-1.jpg","FileSize":197743}
{"FileName":"season-guide-2.jpg","FileSize":200858}

Several options in one request

The response names every refused option at once, and only those:

Shell
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/pdf/to/jpg \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@season-guide.pdf \
  -F ImageWidth=800 \
  -F Rotate=90 \
  -F CropTo=TrimBox
Output
{"Code":400,"Message":"CropTo, Rotate are not supported yet for PDF → JPG"}

ImageWidth isn't named, because PDF to JPG applies it. Both pages of the PDF were rendered before the check ran, and the images were thrown away. The PDF to JPG page lists the options that conversion does read.

Office-suite conversions check first

XLSX to PDF runs on a headless office suite. Conversions that use it also keep a fixed list of options we can't pass to the office suite yet, and they check it before the office suite starts. That check stops at the first match:

Shell
curl -sS -X POST https://api.pdfconversionapi.com/v2/convert/xlsx/to/pdf \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@store-sales-q3.xlsx \
  -F AutoFitColumns=true \
  -F IncludeMetadata=false
Output
{"Code":400,"Message":"AutoFitColumns is not supported yet for XLSX files"}

Remove AutoFitColumns, send it again, and the next one comes up:

Output
{"Code":400,"Message":"IncludeMetadata is not supported yet for XLSX files"}

Without either option, the workbook converts. Sheet and page options, such as WorksheetName, PageSize and FitToPage, are not on this list for spreadsheet to PDF and image conversions, because those conversions apply them.

This list compares values as plain text (ignoring case), not with the loose rules above. On XLSX to PDF, IncludeMetadata=true converts but IncludeMetadata=1 gets a 400, and AutoFitColumns=false converts but AutoFitColumns=0 is refused. If you mean the default, leave the option out.

What the strict rule costs you

  • A multipart request written for ConvertAPI can fail on its first call. Every option it sets away from the default that we don't apply yet gets a 400. For DOCX to PDF, PageRange and Pdfa are refused today. We would rather you find that in a test than in a customer's file.
  • A refusal can take as long as a conversion. Apart from early checks like the one on office-suite conversions, the converter runs to the end before the check, and the output is discarded. The request also counts toward your account's 600 requests per minute, though not toward your plan's monthly conversions, since only successful conversions count.
  • Misspelled names get through. Only names ConvertAPI documents for that conversion are checked. BitDept=8 on PDF to JPG, one letter short, came back 200 with the same two JPGs (197,743 and 200,858 bytes) as a request without it. PageRange on PNG to JPG, which ConvertAPI doesn't document there, is ignored too.
  • Conversions ConvertAPI doesn't document are not checked. 243 of our 556 conversions have no documented list to compare against. png/to/bmp with BitDepth=8 returned 200, with the same 5,760,122-byte BMP as a request without it.
  • An option you leave out gets our default, which is not always ConvertAPI's. PDF to JPG renders pages at 150 DPI unless you set ImageResolution, so a Letter page comes out 1,275 pixels wide; ConvertAPI documents 200. If you depend on a value, send it.
  • Not yet: no API call lists the options a conversion reads, and refused names appear only in the Message text, not in a field of their own. The pages for our main conversions, such as PDF to JPG, list the parameters we read and the ones we refuse.

Handling it in your client

A 400 means the request has to change. Sending it again gets the same answer, so:

  • Don't retry a 400. Retry 429 and 503 after the time in the Retry-After header.
  • Log Message as it is. It names the option.
  • Don't strip the option and resend automatically. That brings back the silent result this check exists to stop. If a setting is optional for you, decide that in code and leave it out of the request.
  • Before you ship, send one real file with the exact options you plan to use, once per conversion. On office-suite conversions such as XLSX to PDF, repeat until no option is named.

Python

Python
import os

import requests


class BadRequest(Exception):
    """The request has to change: sending it again gets the same answer."""


def convert(path, source, target, options):
    with open(path, "rb") as f:
        response = requests.post(
            f"https://api.pdfconversionapi.com/v2/convert/{source}/to/{target}",
            headers={"Authorization": f"Bearer {os.environ['PDFCONVERSIONAPI_KEY']}"},
            files={"File": f},
            data=options,
            timeout=240,
        )
    try:
        body = response.json()
    except ValueError:  # The edge network can refuse an oversized upload with a non-JSON 413
        body = {"Message": response.text[:200]}
    if response.ok:
        return body["Files"]
    if response.status_code == 400:
        raise BadRequest(body["Message"])
    raise RuntimeError(f"{response.status_code}: {body['Message']}")


try:
    convert("season-guide.pdf", "pdf", "jpg", {"BitDepth": "8"})
except BadRequest as err:
    print(f"Not converted: {err}")

Node.js

Save it as convert.mjs:

convert.mjs
import { readFile } from "node:fs/promises";

class BadRequest extends Error {}

async function convert(path, source, target, options) {
  const form = new FormData();
  form.append("File", new Blob([await readFile(path)]), path);
  for (const [name, value] of Object.entries(options)) form.append(name, value);

  const response = await fetch(`https://api.pdfconversionapi.com/v2/convert/${source}/to/${target}`, {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.PDFCONVERSIONAPI_KEY}` },
    body: form,
  });
  const text = await response.text();
  let body;
  try {
    body = JSON.parse(text);
  } catch {
    // The edge network can refuse an oversized upload with a non-JSON 413
    body = { Message: text.slice(0, 200) };
  }
  if (response.ok) return body.Files;
  if (response.status === 400) throw new BadRequest(body.Message);
  throw new Error(`${response.status}: ${body.Message}`);
}

try {
  await convert("season-guide.pdf", "pdf", "jpg", { BitDepth: "8" });
} catch (err) {
  if (!(err instanceof BadRequest)) throw err;
  console.log(`Not converted: ${err.message}`);
}

Both print:

Output
Not converted: BitDepth is not supported yet for PDF → JPG

The rules for parameter names and values are in Requests. To try your own option set, get a free key by signing in at app.pdfconversionapi.com.

How we tested

Date
2026-11-04. Every request and response on this page ran that day, on a build that accepts ImageInterpolation on PNG to JPG and applies ImageWidth on PDF to JPG, and FitToPage and PageSize on XLSX to PDF. An earlier version of this post used those options as refused examples; they now convert, so the examples use options the API still refuses.
Server
Our API running locally in a container, built the same way as our hosted containers, with all engines installed. The hosted API is not deployed yet, so the commands show its address; we ran them with only the base URL changed.
Files
The sample inputs from our PNG to JPG, PDF to JPG, XLSX to PDF and DOCX to PDF pages.
Clients
Curl 8.7.1, jq 1.8.1, Python 3.14.2 with requests 2.34.2, Node.js 24.15.0.
Code read
Our API's source for the option check, and for the fixed list kept by office-suite conversions.

Published

ConvertAPI is a trademark of its owner. We are not affiliated with it.

Written and tested by

Zeel Shekhaliya, Founder

Zeel Shekhaliya is the founder of PDF Conversion API and runs it from Surat, Gujarat, India. Zeel signs the conversion guides and test reports on this site; every number in them comes from a run of the API that you can repeat with the published sample files.

Run your own files through the API.