1. Home
  2. Guides
  3. PDF summary API with Python

Summarize PDFs with Python — PDF Summary API Tutorial

Add PDF summarization to a Python script, a notebook or a backend in a few lines. This tutorial covers authentication, a first request, the response format, streaming, processing a whole folder, and handling errors properly.

Key facts
  • Endpoint: POST https://pdf-summarize.com/api/summarize.php with multipart/form-data, field file.
  • Auth: header Authorization: Bearer sk_... — free key at signup, no credit card.
  • Options: length (short/medium/long/extensive), format (paragraph/bullets/mixed), outputLang (auto or a language code), includeKeywords.
  • Response: JSON with summary, keywords, page_count, processing_time, requests_remaining.
  • Add ?stream=1 to receive the summary as Server-Sent Events.
Updated 2 min read By the PDF Summarizer team

Prerequisites

  • Python 3.8+ and the requests library (pip install requests).
  • An API key: create a free account and copy your key from the dashboard. Store it in an environment variable rather than in code:
export PDF_SUMMARIZE_KEY="sk_live_..."

Your first PDF summary in Python

  1. Install requestspip install requests.
  2. Set your API keyIn the PDF_SUMMARIZE_KEY environment variable.
  3. Send the PDFAs multipart/form-data with the field name file.
  4. Read the JSONThe summary is in summary; check success and the HTTP status.
import os
import requests

API_URL = "https://pdf-summarize.com/api/summarize.php"
API_KEY = os.environ["PDF_SUMMARIZE_KEY"]

def summarize_pdf(path, length="medium", fmt="bullets", lang="auto"):
    with open(path, "rb") as f:
        resp = requests.post(
            API_URL,
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": (os.path.basename(path), f, "application/pdf")},
            data={"length": length, "format": fmt, "outputLang": lang, "includeKeywords": "1"},
            timeout=180,
        )
    data = resp.json()
    if resp.status_code != 200 or not data.get("success"):
        raise RuntimeError(f"{resp.status_code}: {data.get('error', data)}")
    return data

result = summarize_pdf("annual-report.pdf")
print(result["summary"])
print("Pages:", result["page_count"], "| Keywords:", result.get("keywords"))

The response

{
  "success": true,
  "summary": "- Revenue grew 6% to ...",
  "keywords": "revenue, margin, guidance, ...",
  "page_count": 48,
  "original_length": 182340,
  "summary_length": 1210,
  "processing_time": 6.214,
  "requests_remaining": 4987
}

requests_remaining is your remaining monthly quota (-1 means unlimited).

Streaming the summary

For long documents or interactive apps, stream the summary as it's generated:

import json

def stream_summary(path):
    with open(path, "rb") as f:
        with requests.post(
            API_URL + "?stream=1",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": (os.path.basename(path), f, "application/pdf")},
            data={"length": "long", "format": "mixed"},
            stream=True, timeout=300,
        ) as resp:
            resp.raise_for_status()
            for line in resp.iter_lines(decode_unicode=True):
                if not line or not line.startswith("data: "):
                    continue
                payload = line[6:]
                if payload == "[DONE]":
                    break
                event = json.loads(payload)
                if "error" in event:
                    raise RuntimeError(event["error"])
                if event.get("type") == "summary":
                    print(event["content"], end="", flush=True)

stream_summary("research-paper.pdf")

Processing a folder of PDFs

import pathlib, time

out_dir = pathlib.Path("summaries")
out_dir.mkdir(exist_ok=True)

for pdf in sorted(pathlib.Path("pdfs").glob("*.pdf")):
    target = out_dir / (pdf.stem + ".md")
    if target.exists():
        continue                      # resume-friendly
    for attempt in range(3):
        try:
            data = summarize_pdf(str(pdf), length="long", fmt="mixed")
            target.write_text(data["summary"], encoding="utf-8")
            print("ok", pdf.name, data["page_count"], "pages")
            break
        except RuntimeError as e:
            if str(e).startswith("429"):
                time.sleep(30 * (attempt + 1))   # rate limit: back off
            else:
                print("failed", pdf.name, e)
                break

Errors to handle

Status Meaning What to do
400 Missing file, wrong type, page limit exceeded Check the file and your plan's page limit
401 Missing or invalid API key Check the Authorization header
403 Account suspended Contact support
413 File too large Compress or split the PDF
422 No readable text (empty, protected or unreadable scan) Remove password; improve scan
429 Rate limit or monthly quota reached Back off and retry, or upgrade
500 Summarization temporarily unavailable Retry with backoff
Want to test without code first?Try the same engine in your browser, free.
Try the tool →

Tips

  • Set timeouts generously (2-3 minutes) for long PDFs.
  • Cache results by file hash to avoid paying twice for the same document.
  • Keep keys server-side — never ship them in a front-end or mobile app.
  • Full parameter reference: the API documentation.

Frequently asked questions

Is there a free API plan?

Yes. The free plan includes a monthly quota of requests with no credit card. See pricing.

Can I send a PDF URL instead of a file?

The API takes the file itself. Download the PDF in your code (e.g. with requests) and send the bytes.

Which languages can the summary be in?

Use outputLang=auto to keep the document's language, or a language code such as en, fr, es, de.

How do I summarize scanned PDFs through the API?

Send them like any PDF; the extraction pipeline falls back to OCR when there is no usable text layer.

Written by the PDF Summarizer team, who build and run the extraction and summarization pipeline behind this site. We test every method described here on real documents. Last reviewed October 19, 2026. Found an error? Tell us.