What it is
The tools that run on our servers, for your own software: the same engines the UV pdfTool site uses, reached with a key instead of a browser. You create a job, upload the files straight to our storage, start it, and download the result, or let a webhook tell you when it is ready. Everything is JSON over HTTPS at https://uvpdftool.com/api/v1.
- Compress PDF · Makes a PDF smaller
- Office to PDF · Word
- PDF to Office · A PDF into an editable Word (.docx) or PowerPoint (.pptx) file.
- Repair PDF · Rebuilds a damaged PDF from what can still be read.
- PDF to PDF/A · Converts to PDF/A-1b
- OCR · Adds a searchable text layer to scanned pages
- Web page to PDF · Prints a public web page to PDF with a headless browser.
- HTML to PDF · Prints an HTML file
- Markdown to PDF · Typesets a Markdown file
- EPUB to PDF · Prints an e-book without DRM
- PDF to SVG · Each page as an SVG drawing
- Check PDF/A and PDF/UA · Checks conformance with veraPDF and returns a JSON report; the file is not changed.
Make a key on the API keys page (a test key is free), then run the quick start below.
Quick start
One script that compresses report.pdf and writes report-compressed.pdf beside it (results are named by the API). Put your key in the UVPDF_KEY environment variable first; a test key works, and marks the result.
#!/usr/bin/env bash
set -euo pipefail
BASE="https://uvpdftool.com/api/v1"
AUTH="Authorization: Bearer $UVPDF_KEY"
FILE="report.pdf"
SIZE=$(stat -c %s "$FILE" 2>/dev/null || stat -f %z "$FILE")
# 1. Create the job: the tool, its options, and each file's name, size and type.
CREATED=$(curl -sS -X POST "$BASE/jobs" -H "$AUTH" -H "Content-Type: application/json" \
-d "{\"tool\":\"compress\",\"options\":{\"method\":\"ghostscript\",\"preset\":\"ebook\"},
\"files\":[{\"name\":\"$FILE\",\"size\":$SIZE,\"contentType\":\"application/pdf\"}]}")
JOB_ID=$(echo "$CREATED" | jq -r .job.id)
UPLOAD_URL=$(echo "$CREATED" | jq -r '.uploads[0].url')
# 2. Upload the file, as it is, to the link the job gave.
curl -sS -X PUT --upload-file "$FILE" -H "Content-Type: application/pdf" "$UPLOAD_URL"
# 3. Start it.
curl -sS -X POST "$BASE/jobs/$JOB_ID/start" -H "$AUTH" > /dev/null
# 4. Wait for it (or let a webhook tell you).
while :; do
sleep 2
JOB=$(curl -sS "$BASE/jobs/$JOB_ID" -H "$AUTH")
STATE=$(echo "$JOB" | jq -r .job.state)
if [ "$STATE" = done ]; then break; fi
if [ "$STATE" = failed ] || [ "$STATE" = cancelled ]; then echo "$JOB" | jq .job.error; exit 1; fi
done
# 5. Download the result.
OUT=$(echo "$JOB" | jq -r '.job.outputs[0].name')
curl -sS -o "$OUT" "$(echo "$JOB" | jq -r '.job.outputs[0].url')"
echo "Done: $OUT"Needs: cURL curl and jq · Node.js Node.js 18 or later; nothing to install · Python Python 3.9 or later and requests · PHP PHP 8 with the curl extension · Node.js SDK npm install uvpdftool (Node.js 18 or later) · Python SDK pip install uvpdftool (Python 3.9 or later).
The reference has each call on its own with its parameters and answers, and the tools page every option.
Authentication
Every call except GET /tools carries your key as a bearer token:
Authorization: Bearer uvp_live_k3JdQ…- A key is shown once, when it is made; we keep only a fingerprint of it. Lose it and you make another.
- A key is live (
uvp_live_…) or test (uvp_test_…), and may be read-only: then it can read jobs and the account but not make, start or cancel one. - A key can be limited to address ranges, such as
203.0.113.0/24; a call from elsewhere answers403 API_ADDRESS. - Send the key from your server only. Never put it in a web page, a mobile app or a repository: anyone who reads it can spend your tasks.
- Revoking a key refuses it at once, on every request.
Keys, test mode and pricing
| Name | Type | Description |
|---|---|---|
| uvp_live_… | live | Spends one API task for each job that succeeds. A job that fails, is cancelled or never gets its files gives its task back. Tasks come in packs of 1,000 for €19 (priced in your currency at checkout), good for 365 days, on any account: Pro is not needed. |
| uvp_test_… | test | Free: 50 jobs a day, files up to 10 MB, and every result is marked TEST across its pages (conversions out of PDF carry the mark from the input; the PDF/A check says it was a test). The same code runs unchanged against a live key. |
Live and test keys share one account; GET /account says how many tasks and test jobs are left, and we mail you when a pack is four fifths spent and when it is gone. Up to 20 keys per account.
How a job runs
- Create it with
POST /jobs: the tool, its options, and each file’s name, size and content type. The answer carries the job and an upload link per file. - Upload each file with a
PUTto its link, as it is, within 20 minutes. The link goes straight to our storage; the bytes never pass through the API. - Start it with
POST /jobs/{id}/start. Every file is checked for size and presence, and the job joins the queue. - Wait: ask
GET /jobs/{id}every few seconds, or set a webhook and be told. A server picks a job up within seconds; after a quiet spell one is started first, which takes up to half a minute. - Download each output from the
urlthe job carries once it isdone; a link lasts 15 minutes, and reading the job again gives a fresh one.
created ──start──▶ queued ──▶ running ──▶ done
│ └──▶ failed (job.error says why)
└── 20 minutes without its files ──▶ cancelled (the task comes back)
DELETE /jobs/{id} at any point ─────────▶ cancelledA job’s files and results are deleted 2 hours after it ran, or when you delete the job; retentionHours on creation keeps them up to 24 hours. The job record itself stays readable after that, without its files.
Limits
| Name | Type | Description |
|---|---|---|
| requests | 120 / min | Per key. Over it, 429 TOO_MANY_REQUESTS with a Retry-After header. |
| open jobs | 10 | Unfinished jobs per account at once: created, queued or running. |
| files per job | 20 | Declared together; each tool says what it does with several. |
| file size | per tool | Up to 2 GB for Compress and Repair, 500 MB for OCR and PDF/A, 200 MB for the conversions; each tool's page says. 10 MB with a test key. |
| upload window | 20 min | From creation to start. A job left without its files is cancelled and its task returned. |
| run time | per tool | From 3 minutes (web pages) to 60 (OCR); a job over it fails with TIMEOUT. |
| keys | 20 | Per account, live and test together. |
Your files
Files sent to the API are handled as the privacy policy describes for the server tools: processed on our servers in the European Union, stored in a bucket restricted to the European Union, never read by a person in the ordinary course of things, never used to train anything, and deleted when the job’s retention ends or when you delete the job. The job record keeps the file names and sizes, not the files.