May 18, 2026

PDF Compress API: Reduce PDF File Size via a Single API Call

PDF compressreduce PDF sizePDF APIGhostscript

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:

  1. You call POST /api/pdf/compress with a filename that already exists in your account (generated by a previous FUNBREW PDF API call).
  2. The server runs Ghostscript with the selected -dPDFSETTINGS preset.
  3. 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

Related

Powered by FUNBREW PDF