The PDF API
Every ConvertPDF tool over plain HTTPS and JSON: the same engine as the website and the MCP server, with the same daily allowance. Files move over short-lived signed URLs and are deleted within an hour.
Authentication
Create a free key under My account → API and MCP after you sign in, and send it with every request:
Authorization: Bearer cpdf_your_key
Discover
curl https://convertpdf.io/api/v1/me -H "Authorization: Bearer $KEY" curl https://convertpdf.io/api/v1/tools -H "Authorization: Bearer $KEY"
/me returns your plan, today's used units and credits. /tools lists every tool with accepted MIME types, maximum files, options and unit cost.
Convert a file in five calls
# 1. Create the job: file types and exact sizes, in order
curl https://convertpdf.io/api/v1/tools/create_job -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"tool":"compress-pdf","files":[{"mime_type":"application/pdf","bytes":2214019}],"options":{"mode":"images"},"idempotency_key":"a-unique-key-123456"}'
# 2. Get signed upload URLs
curl https://convertpdf.io/api/v1/tools/upload_urls -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"job_id":"JOB_ID"}'
# 3. Upload the raw bytes to each URL with the returned headers
curl -X PUT -H "Content-Type: application/pdf" --data-binary @report.pdf "UPLOAD_URL"
# 4. Seal the upload and start the conversion, then poll until "succeeded"
curl https://convertpdf.io/api/v1/tools/complete_upload -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"job_id":"JOB_ID"}'
curl https://convertpdf.io/api/v1/tools/job_status -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"job_id":"JOB_ID"}'
# 5. Get a download link for an output file
curl https://convertpdf.io/api/v1/tools/download -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"job_id":"JOB_ID","file_id":"FILE_ID"}'
Call delete_job with the same job_id to remove everything right away.
Tools and options
| Tool | Accepts | Options | Units |
|---|---|---|---|
merge-pdf | pdf · up to 20 files | — | 1 |
split-pdf | ranges: Required. One output per range, e.g. "1-3,4,5-9". | 1 | |
organize-pdf | order: Required. New page order listing every page once, e.g. "3,1,2". | 1 | |
rotate-pdf | angle: Required. 90, 180 or 270 (clockwise).ranges: Optional. Pages to rotate, e.g. "2,4-5"; default all. | 1 | |
remove-pages | ranges: Required. Pages to delete, e.g. "2,5-6". | 1 | |
extract-pages | ranges: Required. Pages to keep, in order, e.g. "1,3-4". | 1 | |
compress-pdf | mode: Optional. "structural" (lossless), "images" (recommended, about 150 DPI) or "extreme" (about 100 DPI). Default "images" in the web app; the API default is "structural". | 1 | |
repair-pdf | — | 1 | |
word-to-pdf | docx, msword, vnd.oasis.opendocument.text, rtf | — | 5 |
excel-to-pdf | xlsx, vnd.ms-excel, vnd.oasis.opendocument.spreadsheet | — | 5 |
powerpoint-to-pdf | pptx, vnd.ms-powerpoint, vnd.oasis.opendocument.presentation | — | 5 |
pdf-to-word | language: Optional. OCR language for scanned pages: eng, slv, deu, fra, ita, spa, hrv, por, nld, pol; up to three joined with "+", e.g. "slv+eng". | 5 | |
jpg-to-pdf | jpeg, png, heic, heif, tiff, webp · up to 20 files | page: Optional. "fit" (page matches each image), "a4" or "letter". | 1 |
png-to-pdf | jpeg, png, heic, heif, tiff, webp · up to 20 files | page: Optional. "fit", "a4" or "letter". | 1 |
heic-to-pdf | jpeg, png, heic, heif, tiff, webp · up to 20 files | page: Optional. "fit", "a4" or "letter". | 1 |
tiff-to-pdf | jpeg, png, heic, heif, tiff, webp · up to 20 files | page: Optional. "fit", "a4" or "letter". Every page of a multi-page TIFF becomes a PDF page. | 1 |
webp-to-pdf | jpeg, png, heic, heif, tiff, webp · up to 20 files | page: Optional. "fit", "a4" or "letter". | 1 |
rtf-to-pdf | rtf | — | 5 |
odt-to-pdf | vnd.oasis.opendocument.text | — | 5 |
txt-to-pdf | plain | — | 5 |
html-to-pdf | html | page: Optional. "a4" (default) or "letter"; the page's own @page CSS wins. No JavaScript, no external resources. | 1 |
markdown-to-pdf | markdown, plain | page: Optional. "a4" (default) or "letter". | 1 |
pdf-to-powerpoint | — | 5 | |
pdf-to-jpg | dpi: Optional. 72, 150 or 300.ranges: Optional. Pages to render; default all. Several pages also come as one ZIP. | 1 | |
pdf-to-png | dpi: Optional. 72, 150 or 300.ranges: Optional. Pages to render; default all. | 1 | |
pdf-to-text | — | 1 | |
pdf-to-tiff | dpi: Optional. 72, 150 (default) or 300.color: Optional. "color" (default), "gray" or "bw" (black and white, CCITT Group 4). | 1 | |
resize-pdf | size: Optional. "a4" (default), "letter", "legal", "a3" or "a5".margin: Optional. "none" (default), "small" or "large". | 1 | |
flatten-pdf | — | 1 | |
pdf-to-excel | language: Optional. OCR language for scanned pages, same codes as pdf-to-word. | 5 | |
crop-pdf | mode: Optional. "auto" (default) trims white margins on every page; "area" keeps the rectangle given in box.box: Required when mode is "area". "x0,y0,x1,y1" as fractions of the displayed page from the top-left, e.g. "0.1,0.1,0.9,0.5"; applied to every page. | 1 | |
ocr-pdf | language: Optional. Same codes as pdf-to-word. | 5 | |
pdf-to-pdfa | — | 5 | |
page-numbers | position: Optional. top-left, top-center, top-right, bottom-left, bottom-center (default) or bottom-right.format: Optional. "n" (1), "n-of-total" (1 / 12) or "page-n" (Page 1). | 1 | |
watermark-pdf | text: Required. Up to 60 characters, e.g. "CONFIDENTIAL". | 1 | |
protect-pdf | password: Required. At least 4 characters; AES-256. | 1 | |
unlock-pdf | password: Required. The password that opens the PDF. | 1 | |
sign-pdf | pdf, png · up to 2 files | page: Optional. "first", "last" (default) or a page number.position: Optional. bottom-right (default), bottom-left, bottom-center, top-left, top-right or center.width: Optional. Signature width in points, 60–300. | 1 |
Limits and errors
Up to 100 MB per file. Free accounts get 5 units a day, resetting at midnight UTC. Errors are JSON with an error code, for example daily_limit_reached (429), invalid_file (422) or unauthenticated (401). Retrying a create_job with the same idempotency_key never starts a second job.