pennypdf

Developer API

PDF compression API

PDF compression is the operation with the widest quality-vs-size tradeoff in the format. A naïve compressor ruins scanned receipts; a too-aggressive one softens type. Most commercial APIs expose a single 'compress' knob and hope for the best.

PennyPDF's /v1/compress endpoint runs Ghostscript with three presets (low/medium/strong) corresponding to well-known profiles: /screen (strongest), /ebook (medium), /printer (lightest). Each preset runs three passes: xref/metadata cleanup, JPEG image re-encoding, font subsetting. The API returns the estimated output size in response headers BEFORE streaming the bytes, so you can reject the result if it's not small enough.

1 coin per compression (~$0.04 at the Saver pack, $0.03 at the Pro pack). Compare: Api2pdf ~$0.005/call but requires a paid plan; PDF.co ~$0.01/call same restriction; iLovePDF API $6-$25/month tiered.

Copy, paste, ship

Same bearer-token auth across every endpoint. Set PENNYPDF_API_KEY in your environment first.

curlPOST /v1/compress
curl -X POST https://api.pennypdf.com/v1/compress \
  -H "Authorization: Bearer $PENNYPDF_API_KEY" \
  -F "file=@input.pdf" \
  -F "preset=medium" \
  -i \
  -o compressed.pdf
# Response headers include X-Output-Size-Estimate and X-Coins-Spent
Pythonsize-aware compression with fallback
import os, requests

def compress(path, target_bytes):
    auth = {"Authorization": f"Bearer {os.environ['PENNYPDF_API_KEY']}"}
    for preset in ("low", "medium", "strong"):
        r = requests.post(
            "https://api.pennypdf.com/v1/compress",
            headers=auth,
            files={"file": open(path, "rb")},
            data={"preset": preset},
        )
        if int(r.headers["X-Output-Size-Bytes"]) <= target_bytes:
            return r.content
    raise ValueError(f"{path} cannot shrink below {target_bytes}B")

open("out.pdf", "wb").write(compress("input.pdf", 1_000_000))

How it works

  1. 1POST the PDF + preset (low, medium, strong) to /v1/compress as multipart.
  2. 2Inspect the X-Output-Size-Bytes response header. If too large, retry with a stronger preset.
  3. 31 coin debits once regardless of retry count within the same file — we deduplicate on content hash.

Frequently asked

How much size reduction should I expect?+

Low preset: 10-25% for text-heavy PDFs, up to 40% for image-heavy. Medium: 30-60%. Strong: 50-85% with some visible image softening on photos. The three-pass pipeline (xref cleanup + image resampling + font subsetting) accounts for most of it.

Does compression preserve OCR text?+

Yes. The text layer is never touched by any preset — only images, fonts, and metadata get optimized. PDFs that were searchable before compression stay searchable after.

Latency?+

p50 = 1.8 s for a 10 MB PDF, p90 = 4.2 s for 50 MB, p99 = 12 s for 200 MB. Compression is single-core; multi-file pipelines should parallelize at the client level for throughput.

Rate limits?+

100 synchronous compressions per minute per API key. For higher throughput, use the async endpoint with job polling — async has no per-minute cap, only coin balance.

Can I preview the size without paying?+

Send `?dry_run=true`. You get back the X-Output-Size-Estimate header and no file body, for 0 coins. Good for rejecting compressions that wouldn't hit your upload cap anyway.

Is digital signature preserved?+

No — compression re-serializes the PDF, which invalidates cryptographic signatures. For signed PDFs, sign AFTER compressing, not before. /v1/sign supports the chained workflow in a single request.

Why PennyPDF

  • No subscription. Ever.
  • Coins never expire — use them in 5 years.
  • Client-side processing for 14 of 22 tools.
  • No watermarks at any tier.
  • Per-operation pricing, shown before you click.
  • Same coins for web + public API.