v1.0 · Live

API Reference

Send us a PDF, we send back a summary. One endpoint, a multipart file upload, a JSON response — built to drop into a backend job or a document pipeline in a few minutes.

Overview

The PDF Summarizer API takes a PDF file as input — not a block of text you have to paste or extract yourself — and returns a clean, structured summary. Under the hood it runs the file through a multi-method text-extraction pipeline (including OCR for scanned pages) before handing the extracted content to an LLM.

Base URL

Base URL https://pdf-summarize.com/api

Key capabilities

Authentication

Every request needs a valid API key in the Authorization header, using the Bearer scheme.

HTTP Header
Authorization: Bearer YOUR_API_KEY
🔑
Get your API key Create a free account at pdf-summarize.com/signup — your key is generated instantly and visible on your API keys page. Free tier includes 50 PDF summaries/month, no card required.

API key format

Keys look like sk_live_xxxxxxxxxxxxxxxxxxxxxxxx in production (or sk_test_... in a test environment). Treat your key like a password — anyone holding it can spend your monthly quota.

Quick Start

POST a PDF to /api/summarize as multipart/form-data — the file goes in a field named file, everything else is an optional form field alongside it.

# -F sends the file and form fields as multipart/form-data

curl -X POST https://pdf-summarize.com/api/summarize \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "length=medium"
const summarizePdf = async (file) => {
  const form = new FormData();
  form.append('file', file);
  form.append('length', 'medium');

  const res = await fetch('https://pdf-summarize.com/api/summarize', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
    body: form // no Content-Type header — the browser sets the multipart boundary
  });
  const data = await res.json();
  console.log(data.summary);
};

// <input type="file" id="pdf" accept="application/pdf">
summarizePdf(document.getElementById('pdf').files[0]);
import requests

with open("report.pdf", "rb") as f:
    response = requests.post(
        "https://pdf-summarize.com/api/summarize",
        headers={"Authorization": "Bearer YOUR_API_KEY"},
        files={"file": f},
        data={"length": "medium"}
    )

data = response.json()
print(data["summary"])
<?php
$ch = curl_init('https://pdf-summarize.com/api/summarize');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => [
        'file'   => new CURLFile('report.pdf', 'application/pdf'),
        'length' => 'medium'
    ]
]);
$data = json_decode(curl_exec($ch), true);
echo $data['summary'];

Example response

JSON Response · 200 OK
{
  "success": true,
  "summary": "A concise summary of the document.",
  "keywords": null,
  "page_count": 12,
  "original_length": 18420,
  "summary_length": 612,
  "processing_time": 4.31,
  "requests_remaining": 48
}

File Requirements & OCR

Extraction runs through a cascade of methods so a single bad PDF doesn't fail the whole request: an embedded-text parser is tried first, then a couple of lower-level fallbacks, and if the document looks like it's mostly scanned images, OCR kicks in automatically. You never choose a method — the API picks whatever gets the most usable text out of the file you sent.

LimitDefaultNotes
Max file size20 MBLarger files return 413.
Max pages300Longer documents return 400 before any extraction is attempted.
File typeapplication/pdf onlyChecked by both MIME type and file extension.
⚠️
Password-protected or empty PDFsA file that yields under 50 characters of usable text after extraction (encrypted, corrupted, or a blank scan with no OCR-readable content) returns 422 rather than a low-quality summary.

Endpoint

The API exposes a single endpoint for uploading and summarizing a PDF.

POST /api/summarize

Accepts a PDF file plus optional form fields, returns a structured JSON summary.

Request headers

HeaderValueRequired
Authorization Bearer YOUR_API_KEY Required
Content-Type multipart/form-data Set automatically by your HTTP client when you send a file

Request Parameters

Send as multipart/form-data. Only file is required — everything else has a sensible default.

FieldTypeDefaultDescription
file
required
file The PDF to summarize. Max 20MB, max 300 pages.
length
optional
string medium Output length.
short — 2–3 sentences
medium — 1 paragraph
long — 2–3 paragraphs
extensive — 4–5 paragraphs
style
optional
string professional Writing style.
professional casual academic technical simple
format
optional
string paragraph Output format.
paragraph — flowing prose
bullets — bullet point list
mixed — short paragraph + key bullets
outputLang
optional
string auto Output language. auto matches the document's language, or pass any ISO 639-1 code:
en fr es de it pt ar zh ja ru
includeKeywords
optional
boolean false Send as "true" to extract 5–7 key terms into the keywords field.
max_length
optional
integer Hard cap on the summary length in characters. Overrides length when set.

Response Format

All responses are JSON. A successful request returns HTTP 200.

Response fields

FieldTypeDescription
successbooleanAlways true on success.
summarystringThe generated summary text.
keywordsstring | nullnull unless includeKeywords was true.
page_countinteger | nullPage count of the uploaded PDF, when detectable.
original_lengthintegerCharacter count of the text extracted from the PDF.
summary_lengthintegerCharacter count of the summary.
processing_timefloatTotal time in seconds, extraction included.
requests_remainingintegerRemaining requests in the current billing period. -1 on unlimited plans.

Streaming (SSE)

Append ?stream=1 to get the summary as Server-Sent Events instead of a single JSON blob. Extraction still happens up front (it isn't itself streamed) — once the document's text is ready, summary tokens stream back as they're generated.

ℹ️
NoteSame multipart upload and same auth as the standard endpoint — only the query string and response format differ.
POST /api/summarize?stream=1

Event format

The stream emits data: lines, each carrying a JSON payload with a type field:

typeFieldsDescription
summarycontentIncremental text token. Append these to build the full summary.
donesummaryStream complete. summary holds the full text.
errorerrorSomething failed. The stream closes right after.

The stream always ends with a bare data: [DONE] line — use it to know the connection closed, independent of whether the last real event was done or error.

JavaScript streaming example

JavaScript · Fetch + ReadableStream
const streamSummary = async (file, onChunk, onDone) => {
  const form = new FormData();
  form.append('file', file);

  const res = await fetch('https://pdf-summarize.com/api/summarize?stream=1', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
    body: form
  });

  const reader = res.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const lines = decoder.decode(value).split('\n');
    for (const line of lines) {
      if (!line.startsWith('data: ')) continue;
      if (line === 'data: [DONE]') continue;
      const event = JSON.parse(line.slice(6));
      if (event.type === 'summary') onChunk(event.content);
      if (event.type === 'done')    onDone(event.summary);
    }
  }
};

// Usage
streamSummary(
  document.getElementById('pdf').files[0],
  chunk => process.stdout.write(chunk),
  full  => console.log('\n\nDone. Full summary:', full)
);

Errors

Error responses include an error field describing what went wrong. HTTP status codes follow standard conventions.

Error Response
{
  "error": "Invalid API key"
}
StatusErrorDescription
400 Invalid request Missing file, wrong MIME type, malformed upload, or the PDF exceeds the page limit.
401 Unauthorized Missing or invalid API key. Check the Authorization header.
403 Account suspended Contact support.
405 Method not allowed Only POST requests are accepted.
413 File too large Exceeds the 20MB size limit.
422 Unprocessable PDF Extraction failed or found under 50 characters of usable text (scanned with no OCR-readable content, encrypted, or empty).
429 Rate limit exceeded Either the 60-requests/minute burst limit or your monthly quota. Check Retry-After on the burst case.
500 Server error All summarization providers were unavailable. Retry with backoff; if it persists, contact support.

cURL Examples

Complete examples using curl — available on Linux, macOS, and Windows.

Standard request

cURL
curl -X POST https://pdf-summarize.com/api/summarize \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "length=short" \
  -F "style=professional" \
  -F "format=paragraph" \
  -F "outputLang=en" \
  -F "includeKeywords=true"

With streaming

cURL · Streaming
curl -X POST "https://pdf-summarize.com/api/summarize?stream=1" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  --no-buffer

# Output (streamed):
# data: {"type":"summary","content":"The report"}
# data: {"type":"summary","content":" outlines"}
# ...
# data: {"type":"done","summary":"Full summary text."}
# data: [DONE]

JavaScript Examples

Works in browsers and Node.js (v18+, for FormData/fetch). For older Node, install form-data and node-fetch.

class PdfSummarizerClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseURL = 'https://pdf-summarize.com/api';
  }

  async summarize(file, options = {}) {
    const form = new FormData();
    form.append('file', file);
    for (const [k, v] of Object.entries(options)) form.append(k, v);

    const res = await fetch(`${this.baseURL}/summarize`, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${this.apiKey}` },
      body: form
    });

    if (!res.ok) {
      const err = await res.json();
      throw new Error(err.error);
    }
    return res.json();
  }
}

// Usage
const client = new PdfSummarizerClient('YOUR_API_KEY');

const result = await client.summarize(
  document.getElementById('pdf').files[0],
  { length: 'medium', style: 'professional', includeKeywords: 'true' }
);

console.log('Summary:', result.summary);
console.log('Pages:', result.page_count);
console.log('Compression:', Math.round((1 - result.summary_length / result.original_length) * 100) + '%');
// npm install axios form-data
const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const client = axios.create({
  baseURL: 'https://pdf-summarize.com/api',
  headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
});

async function summarize(path, options = {}) {
  const form = new FormData();
  form.append('file', fs.createReadStream(path));
  for (const [k, v] of Object.entries(options)) form.append(k, v);

  const { data } = await client.post('/summarize', form, { headers: form.getHeaders() });
  return data;
}

summarize('report.pdf', { length: 'short' })
  .then(r => console.log(r.summary))
  .catch(e => console.error(e.response?.data?.error));

Python Examples

Requires Python 3.7+ and the requests library (pip install requests).

import requests

class PdfSummarizerClient:
    BASE_URL = "https://pdf-summarize.com/api"

    def __init__(self, api_key: str):
        self.session = requests.Session()
        self.session.headers.update({"Authorization": f"Bearer {api_key}"})

    def summarize(self, path: str, **fields) -> dict:
        with open(path, "rb") as f:
            response = self.session.post(
                f"{self.BASE_URL}/summarize",
                files={"file": f},
                data=fields
            )
        response.raise_for_status()
        return response.json()


# Usage
client = PdfSummarizerClient("YOUR_API_KEY")

result = client.summarize(
    "report.pdf",
    length="medium",
    style="academic",
    outputLang="en",
    includeKeywords="true"
)

print(f"Summary: {result['summary']}")
print(f"Pages: {result['page_count']}")
print(f"Reduced by {100 - round(result['summary_length'] / result['original_length'] * 100)}%")
# pip install httpx
import asyncio
import httpx

async def summarize(api_key: str, path: str, **fields) -> dict:
    async with httpx.AsyncClient() as client:
        with open(path, "rb") as f:
            response = await client.post(
                "https://pdf-summarize.com/api/summarize",
                headers={"Authorization": f"Bearer {api_key}"},
                files={"file": f},
                data=fields
            )
        response.raise_for_status()
        return response.json()

# Usage
result = asyncio.run(summarize(
    "YOUR_API_KEY",
    "report.pdf",
    length="short"
))
print(result["summary"])

PHP Examples

Works with PHP 7.4+. Uses cURL (enabled by default in most PHP installations).

<?php

class PdfSummarizerClient {
    private string $apiKey;
    private string $baseUrl = 'https://pdf-summarize.com/api';

    public function __construct(string $apiKey) {
        $this->apiKey = $apiKey;
    }

    public function summarize(string $pdfPath, array $fields = []): array {
        $ch = curl_init($this->baseUrl . '/summarize');
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $this->apiKey],
            CURLOPT_POSTFIELDS     => array_merge(
                ['file' => new CURLFile($pdfPath, 'application/pdf')],
                $fields
            ),
            CURLOPT_TIMEOUT        => 120
        ]);
        $body     = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            $err = json_decode($body, true);
            throw new \RuntimeException($err['error'] ?? 'API error');
        }
        return json_decode($body, true);
    }
}

// Usage
$client = new PdfSummarizerClient('YOUR_API_KEY');

$result = $client->summarize('report.pdf', [
    'length' => 'medium',
    'includeKeywords' => 'true'
]);

echo $result['summary'] . PHP_EOL;
echo $result['page_count'] . ' pages' . PHP_EOL;
<?php
// composer require guzzlehttp/guzzle
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://pdf-summarize.com/api/',
    'headers'  => ['Authorization' => 'Bearer YOUR_API_KEY']
]);

$response = $client->post('summarize', [
    'multipart' => [
        ['name' => 'file', 'contents' => fopen('report.pdf', 'r')],
        ['name' => 'length', 'contents' => 'medium'],
        ['name' => 'includeKeywords', 'contents' => 'true']
    ]
]);

$data = json_decode($response->getBody(), true);
echo $data['summary'];

Plans & Limits

Request quotas are enforced per calendar month and reset on the 1st. A separate burst limit of 60 requests/minute applies to every plan.

PlanPDF summaries / monthAPI access
Free 50 Full API access
Professional — $9/mo 1,000 Full API access + priority processing
Business — $19/mo Unlimited Full API access + dedicated support + SLA 99.9%

Past your monthly quota, the API returns HTTP 429. Every successful response includes requests_remaining so you can track usage without a separate call.

ℹ️
Need more headroom? Upgrade from your billing page — it takes effect immediately, no waiting for the next cycle.

Changelog

2026-07
v1.0 Latest
  • Multipart PDF upload endpoint (/api/summarize)
  • Multi-method text extraction with automatic OCR fallback for scanned pages
  • Real-time SSE streaming, once extraction completes
  • 5 writing styles, 4 output formats, auto-detected output language
  • API key authentication, free tier with no card required

Have a feature request or found a bug? Contact us — we read every message.