PDF Compress API: Reduce PDF File Size via a Single API Call
Email inboxes bounce large PDFs. Download links time out. Storage costs accumulate. When a PDF is too big, the most practical fix is compression — and doing it server-side via API means no extra library or local tool required.
FUNBREW PDF's compress endpoint (POST /api/pdf/compress) takes an existing PDF stored on the FUNBREW server, runs it through Ghostscript, and returns a new download URL for the compressed file. One POST request, one download URL.
This guide covers the full API specification, quality preset breakdown, working code in cURL, Node.js, Python, and PHP, and practical tips for maximizing compression ratio.
For generating PDFs before compressing them, see the PDF API Quickstart. For merging multiple PDFs into one, see the PDF Merge API Guide.
How It Works
The compression pipeline has three steps:
- You call
POST /api/pdf/compresswith afilenamethat already exists in your account (generated by a previous FUNBREW PDF API call). - The server runs Ghostscript with the selected
-dPDFSETTINGSpreset. - If the compressed output is smaller than the original, the API stores and returns the compressed file. If not, it returns the original — you always get a valid result.
The endpoint requires the pdf.feature:compress feature gate on your plan (SaaS edition only).
API Specification
POST /api/pdf/compress
Content-Type: application/json
Authorization: Bearer {API key}
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
filename |
string | Yes | Filename of an existing PDF in your account |
quality |
string | No | Compression preset: low, medium, or high (default: medium) |
expiration_hours |
integer | No | Lifetime of the compressed file in hours (0–168, default 24) |
max_downloads |
integer | No | Maximum download count before expiry (0–100, default 10) |
Quality Presets
The quality parameter maps to Ghostscript's -dPDFSETTINGS flag:
| Value | Ghostscript setting | Typical use |
|---|---|---|
low |
/screen |
Email attachments, previews — maximum size reduction |
medium |
/ebook |
Web distribution, business documents — balanced (default) |
high |
/printer |
Print-ready output — minimal quality loss |
Success Response
{
"success": true,
"data": {
"filename": "compressed-abc123.pdf",
"download_url": "https://pdf.funbrew.cloud/api/pdf/download/compressed-abc123.pdf",
"original_size": 4194304,
"compressed_size": 1048576,
"savings_percent": 75.0,
"expires_at": "2026-05-19T10:00:00Z"
}
}
savings_percent is the percentage reduction from original_size to compressed_size. A value of 0 means the original was already optimal and the API returned it unchanged.
Error Responses
| Status | Reason |
|---|---|
| 422 | filename not found in your account, or file is expired |
| 422 | File not found on storage (already deleted) |
| 500 | Ghostscript execution failed |
Code Examples
cURL
The minimal example — compress with the default medium quality:
curl -X POST https://pdf.funbrew.cloud/api/pdf/compress \
-H "Authorization: Bearer $FUNBREW_PDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "report-abc123.pdf",
"quality": "medium"
}'
Specify low quality and a 48-hour expiration:
curl -X POST https://pdf.funbrew.cloud/api/pdf/compress \
-H "Authorization: Bearer $FUNBREW_PDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "report-abc123.pdf",
"quality": "low",
"expiration_hours": 48,
"max_downloads": 5
}'
Node.js
const fs = require('fs');
async function compressPdf(filename, quality = 'medium') {
const response = await fetch('https://pdf.funbrew.cloud/api/pdf/compress', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FUNBREW_PDF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ filename, quality }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Compress API error ${response.status}: ${error.message}`);
}
const result = await response.json();
const { download_url, original_size, compressed_size, savings_percent } = result.data;
console.log(`Original: ${(original_size / 1024).toFixed(1)} KB`);
console.log(`Compressed: ${(compressed_size / 1024).toFixed(1)} KB`);
console.log(`Saved: ${savings_percent}%`);
console.log(`Download: ${download_url}`);
return result.data;
}
// Two-step example: generate → compress
async function generateAndCompress() {
// Step 1: Generate PDF
const genResponse = await fetch('https://pdf.funbrew.cloud/api/pdf/generate-from-html', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FUNBREW_PDF_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: '<h1>Annual Report</h1><p>Fiscal year 2026 summary...</p>',
engine: 'quality',
format: 'A4',
return_type: 'filename',
}),
});
const genResult = await genResponse.json();
const filename = genResult.data.filename;
// Step 2: Compress
const compressed = await compressPdf(filename, 'low');
return compressed.download_url;
}
generateAndCompress().then(url => console.log('Final URL:', url));
Python
import os
import requests
FUNBREW_API_KEY = os.environ["FUNBREW_PDF_API_KEY"]
BASE_URL = "https://pdf.funbrew.cloud/api/pdf"
def compress_pdf(filename: str, quality: str = "medium") -> dict:
"""Compress a PDF stored on FUNBREW and return the result metadata."""
response = requests.post(
f"{BASE_URL}/compress",
headers={"Authorization": f"Bearer {FUNBREW_API_KEY}"},
json={"filename": filename, "quality": quality},
timeout=60,
)
response.raise_for_status()
result = response.json()["data"]
print(f"Original: {result['original_size'] / 1024:.1f} KB")
print(f"Compressed: {result['compressed_size'] / 1024:.1f} KB")
print(f"Saved: {result['savings_percent']}%")
return result
def generate_and_compress(html: str, quality: str = "medium") -> str:
"""Generate a PDF from HTML, then compress it. Returns the download URL."""
# Step 1: Generate
gen_response = requests.post(
f"{BASE_URL}/generate-from-html",
headers={"Authorization": f"Bearer {FUNBREW_API_KEY}"},
json={
"html": html,
"engine": "quality",
"format": "A4",
"return_type": "filename",
},
timeout=60,
)
gen_response.raise_for_status()
filename = gen_response.json()["data"]["filename"]
# Step 2: Compress
result = compress_pdf(filename, quality)
return result["download_url"]
if __name__ == "__main__":
html = """
<html><body>
<h1>Quarterly Report</h1>
<p>This report contains high-resolution images and detailed charts.</p>
</body></html>
"""
url = generate_and_compress(html, quality="low")
print(f"Download URL: {url}")
PHP
cURL (framework-agnostic)
function compressPdf(string $filename, string $quality = 'medium'): array
{
$ch = curl_init('https://pdf.funbrew.cloud/api/pdf/compress');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('FUNBREW_PDF_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'filename' => $filename,
'quality' => $quality,
]),
]);
$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new RuntimeException("Compress API returned HTTP $httpCode: $body");
}
$result = json_decode($body, true)['data'];
printf(
"Original: %.1f KB | Compressed: %.1f KB | Saved: %s%%\n",
$result['original_size'] / 1024,
$result['compressed_size'] / 1024,
$result['savings_percent']
);
return $result;
}
// Usage
$result = compressPdf('report-abc123.pdf', 'low');
echo $result['download_url'];
Laravel (Http Facade)
use Illuminate\Support\Facades\Http;
$response = Http::withToken(config('services.funbrew.api_key'))
->post('https://pdf.funbrew.cloud/api/pdf/compress', [
'filename' => 'report-abc123.pdf',
'quality' => 'medium',
'expiration_hours' => 48,
'max_downloads' => 20,
]);
if ($response->successful()) {
$data = $response->json('data');
logger()->info('PDF compressed', [
'savings_percent' => $data['savings_percent'],
'download_url' => $data['download_url'],
]);
}
Two-Step Pattern: Generate Then Compress
The compress endpoint works on files already stored in your FUNBREW account. When your PDF generation endpoint uses return_type: "filename", the generated PDF stays on the server and its filename is returned in the response. Pass that filename directly to /api/pdf/compress.
POST /api/pdf/generate-from-html → { filename: "gen-abc.pdf" }
POST /api/pdf/compress → { filename: "compressed-xyz.pdf", savings_percent: 68.3 }
This two-step approach is useful for:
- Report generation pipelines: Generate a complex HTML report (quality engine), then compress the output before emailing.
- Certificate batch jobs: Generate certificates, compress each one, then merge into a single archive. See the PDF Certificate Automation Guide.
- Storage-conscious workflows: Compress before archiving to an S3 bucket or Wasabi storage.
Practical Tips
Choosing a Quality Preset
- low (
/screen): Aggressively downsamples images to 72 dpi. Best for email delivery or previews where visual quality is secondary to file size. Avoid for documents with fine charts or small text. - medium (
/ebook): Downsamples to 150 dpi. The right default for most web distribution, SaaS document exports, and dashboard downloads. - high (
/printer): Downsamples to 300 dpi. Use when the document will be printed or when image clarity is critical.
When Compression Has Minimal Effect
PDFs that are already heavily compressed — such as scanned image-only PDFs or files previously processed by Ghostscript — may not shrink further. The API handles this automatically: if the output is not smaller than the input, you receive the original content unchanged (savings_percent: 0).
To avoid wasted API calls on files that are already small (under 200 KB), check the file size from a previous API response before calling the compress endpoint.
Expiration and Download Limits
By default, the compressed file expires after 24 hours with a 10-download limit. For batch pipelines where the file is immediately downloaded or transferred to external storage, these defaults are reasonable. For longer-lived downloads (e.g., a link emailed to a customer), set expiration_hours up to 168 (7 days).
Comparison with Alternatives
| Approach | Setup | Accuracy | API call required |
|---|---|---|---|
| FUNBREW PDF compress API | Zero — HTTP only | Ghostscript (/screen, /ebook, /printer) | Yes |
| Local Ghostscript | Install + maintain Ghostscript binary | Same presets | No |
| PyPDF2 / pypdf | pip install | Limited compression options | No |
| Adobe Acrobat | Desktop/cloud license | High | No |
| iLovePDF / ConvertAPI | Third-party SaaS | Varies | Yes |
The main advantage of using the FUNBREW PDF compress API over local Ghostscript is that there is nothing to install or maintain on your server — especially relevant in serverless and container environments where binary dependencies are a liability. Compared to generic third-party compress services, you stay within the same API contract and credentials you already use for PDF generation.
Next Steps
- API Reference — compress endpoint: Full parameter documentation
- Playground: Test PDF generation and download links before integrating
- PDF Merge API Guide: Combine multiple PDFs after compression
- PDF API Batch Processing Guide: High-volume pipelines using concurrency
- PDF Certificate Automation Guide: Bulk certificate generation and compression
Related
- PDF API Quickstart: Node.js, Python & PHP — First API call in under 5 minutes
- PDF Merge API Guide — Combine PDFs into one file
- Use Cases — Real-world PDF automation patterns