How this differs from our website tools: the free tools on editpdf.tools run in your browser and never upload your files. The API is different by design: your PDF is sent over HTTPS to our processing server, compressed, returned in the same response, and deleted right after. Details are in the API terms and data handling.
Quick start
Send the PDF as multipart/form-data with your key in the X-API-Key header. The response body is the compressed PDF.
curl -X POST https://api.editpdf.tools/v1/compress \
-H "X-API-Key: YOUR_KEY" \
-F "file=@input.pdf" \
-F "level=recommended" \
-o compressed.pdf
Python
import requests
with open("input.pdf", "rb") as f:
r = requests.post(
"https://api.editpdf.tools/v1/compress",
headers={"X-API-Key": "YOUR_KEY"},
files={"file": ("input.pdf", f, "application/pdf")},
data={"level": "recommended"},
timeout=180,
)
if r.status_code == 200:
open("compressed.pdf", "wb").write(r.content)
print(r.headers["X-Original-Size"], "->", r.headers["X-Compressed-Size"])
else:
print(r.status_code, r.json())
Node.js (18 or newer)
import { readFile, writeFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("input.pdf")], { type: "application/pdf" }), "input.pdf");
form.append("level", "recommended");
const res = await fetch("https://api.editpdf.tools/v1/compress", {
method: "POST",
headers: { "X-API-Key": process.env.EDITPDF_API_KEY },
body: form,
});
if (res.ok) await writeFile("compressed.pdf", Buffer.from(await res.arrayBuffer()));
else console.error(res.status, await res.json());
Endpoints
POST /v1/compress
| Field | Where | Details |
|---|---|---|
X-API-Key | Header | Required. Authorization: Bearer YOUR_KEY also works. |
file | Form field | Required. One PDF file. |
level | Form field or query | Optional. light, recommended (default) or strong. |
A successful call returns 200 with the PDF (application/pdf) and these headers:
X-Original-SizeandX-Compressed-Size: sizes in bytes.X-Compressed:falsemeans compression did not make the file smaller, so you get your original file back unchanged.X-Level: the level used.X-Quota-Remaining: files left this month.
GET /v1/me
Checks your key and returns your current limits and usage, for example:
{"email":"you@example.com","month":"2026-11","files_used":3,"monthly_quota":30,
"files_remaining":27,"max_file_mb":10,"seconds_between_files":60}
Compression levels
| Level | Images are resampled to | Use it for |
|---|---|---|
light | 300 dpi | Print quality, smallest change |
recommended | 150 dpi | Email, uploads and forms (default) |
strong | 72 dpi | Smallest file, screen viewing only |
Scanned and photo-heavy PDFs shrink the most. Text-only or already optimized PDFs may not get smaller; in that case the original is returned.
Limits (free plan)
| Limit | Value |
|---|---|
| Max file size | 10 MB |
| Files per month | 30 (resets on the 1st, UTC) |
| Rate | 1 file per minute |
| Input | PDF only. Password-protected PDFs are not supported. |
Processing time. Most text PDFs finish in a few seconds. Scanned or image-heavy PDFs close to 10 MB can take up to about 2 minutes on the free plan, so set your HTTP client timeout to at least 180 seconds. If the service has been idle it may also need up to a minute to start; in that case retry after the time in the Retry-After header.
Errors
Errors are JSON, for example {"error":"file_too_large","max_mb":10,"message":"File must be 10 MB or smaller on your plan."}
| Status | error | What to do |
|---|---|---|
| 400 | missing_file, bad_level | Send the PDF in the file field; use a valid level. |
| 401 | invalid_api_key | Check the key, or create a new one in your dashboard. |
| 403 | account_blocked | Contact support. |
| 411 | content_length_required | Send a normal upload with a Content-Length header. |
| 413 | file_too_large | Use a file within max_mb. |
| 415 | use_multipart_form_data, not_a_pdf | Send multipart/form-data with a real PDF. |
| 422 | pdf_is_password_protected, could_not_read_pdf, could_not_process_pdf | Remove the password or repair the PDF, then try again. |
| 429 | rate_limited, monthly_quota_reached | Wait retry_after_seconds, or until next month. |
| 503 | service_starting_retry_in_60s, processing_timeout, service_capacity_reached_this_month, temporarily_unavailable | Retry later. A timeout usually means the file is too heavy; try strong or a smaller file. |
Your files and data
- Files travel over HTTPS, are compressed with Ghostscript and are deleted as soon as the response is sent. We do not keep copies.
- We store your email, a hash of your API key and monthly usage counts. We never store the key itself.
- Full details: API terms and data handling.
Open source
The API code is public under the AGPL-3.0 license: github.com/chanbuilsdai/compress-pdf-api. Compression uses the unmodified Ghostscript program by Artifex Software (AGPL) and qpdf (Apache-2.0) for file checks.
Support
Questions or a higher limit for a project? Use the contact form or email support@editpdf.tools. Prefer no code? Our Compress PDF tool works in your browser without uploading the file.