How to compress a PDF via API (Python and Node.js)
Large PDFs slow down uploads, blow past email limits, and cost you storage. This guide shows how to shrink a PDF from your own code with a single HTTP request, with copy-paste examples in curl, Python, and Node.js.
Why compress PDFs in code
Doing it by hand in a desktop app does not scale. When your app accepts PDF uploads, generates reports, or emails invoices, you want compression to happen automatically in your backend. A small API call keeps your code simple and your files small, without bundling a heavy PDF engine into your own service.
FileAlloy exposes a single endpoint for this: POST /v1/compress. It takes a PDF and returns a smaller one. Files are processed in memory and deleted the moment the response is sent, so nothing is stored.
Step 1: Get an API key
Create a free account at app.filealloy.com and generate a key. You pass it in the X-API-Key header on every request. The free plan is enough to test and build.
Step 2: A quick test with curl
Before writing any code, confirm it works from your terminal:
curl -X POST https://api.filealloy.com/v1/compress \
-H "X-API-Key: fa_live_your_key" \
-F "file=@input.pdf" \
-F "level=medium" \
-o compressed.pdf You now have a compressed.pdf next to your input. The level field is optional and controls the quality/size trade-off (more on that below).
Step 3: Compress a PDF in Python
Using the requests library, send the file as multipart form data and write the response bytes to disk:
import requests
with open("input.pdf", "rb") as f:
resp = requests.post(
"https://api.filealloy.com/v1/compress",
headers={"X-API-Key": "fa_live_your_key"},
files={"file": ("input.pdf", f, "application/pdf")},
data={"level": "medium"},
)
resp.raise_for_status()
with open("compressed.pdf", "wb") as out:
out.write(resp.content)
print("Saved", len(resp.content), "bytes") Step 4: Compress a PDF in Node.js
Node 18+ ships with fetch, FormData, and Blob built in, so there are no dependencies to install:
import { readFile, writeFile } from "node:fs/promises";
const bytes = await readFile("input.pdf");
const form = new FormData();
form.append("file", new Blob([bytes], { type: "application/pdf" }), "input.pdf");
form.append("level", "medium");
const res = await fetch("https://api.filealloy.com/v1/compress", {
method: "POST",
headers: { "X-API-Key": "fa_live_your_key" },
body: form,
});
if (!res.ok) throw new Error(`Compress failed: ${res.status}`);
const out = Buffer.from(await res.arrayBuffer());
await writeFile("compressed.pdf", out);
console.log("Saved", out.length, "bytes"); Choosing a compression level
The optional level field trades size against quality:
low- smallest file (images down to 72dpi). Best for on-screen viewing and email.medium- balanced (150dpi). A good default for most documents.high- best quality (300dpi). Use when the PDF will be printed.
How much you save depends on the content. Image-heavy PDFs and scans shrink the most; a text-only PDF is already small, so expect modest gains.
Handling errors and quotas
The API returns standard HTTP status codes. A 401 means the key is missing or wrong, a 400 means the input was not a valid PDF, and a 429 means you hit your plan's monthly quota. Each response also carries X-Quota-Limit and X-Quota-Used headers so you can track usage. Always check the status before writing the output, as both examples above do.
Summary
One endpoint, one call, a smaller PDF back. The operation is deterministic and stateless, so you can run it in parallel across a batch. Files are never stored, so it is safe for sensitive documents. The other operations follow the same shape: swap the path to convert to Word, run OCR, or merge, and the request looks almost identical.