← Blog

Claude API for Data Extraction from PDFs

2026-10-27 · 6 min read · SubToAPI Team

Pulling structured data out of PDFs — invoices, contracts, resumes, financial statements, scanned forms — is one of the most common and most annoying backend tasks. Traditional OCR plus regex pipelines break the moment a layout changes. The Claude API solves this differently: you send the document (or its extracted text) along with a prompt describing exactly what fields you want, and Claude returns structured data, usually JSON, regardless of how the document is formatted.

This article covers the practical approach: how to prepare PDFs for Claude, how to write prompts that produce reliable structured output, how to handle multi-page and scanned documents, and how to wire this into an API-based workflow using SubToAPI as the access layer.

Why Claude Is Good at PDF Data Extraction

Claude handles PDF extraction well for a few reasons:

The tradeoff is that Claude works with text, not raw PDF bytes. So the first real decision in any extraction pipeline is how you get text out of the PDF before it reaches the model.

Step 1: Convert the PDF to Text

For most PDFs (not scanned images), extract the text layer directly using a library like pdf-parse (Node.js) or pdfplumber (Python). This is fast, cheap, and preserves most of the structure Claude needs.

import pdf from "pdf-parse";
import fs from "fs";

const buffer = fs.readFileSync("invoice.pdf");
const data = await pdf(buffer);
const text = data.text; // raw text, ready to send to Claude

For scanned PDFs with no embedded text layer, run OCR first (Tesseract, or a cloud OCR service) and feed the resulting text into the same pipeline. Claude's extraction quality depends heavily on OCR quality, so if you're dealing with low-resolution scans, invest in cleaning up the OCR output before sending it to the model.

Step 2: Write a Prompt With a Defined Schema

The key to reliable extraction is being explicit about the exact fields you want and the exact format of the response. Vague prompts like "extract the important information" produce inconsistent results. Specific prompts with a JSON schema produce consistent, parseable output.

Extract the following fields from this invoice text and return ONLY valid JSON,
no explanation, no markdown formatting:

{
  "invoice_number": string,
  "invoice_date": string (YYYY-MM-DD),
  "due_date": string (YYYY-MM-DD) or null,
  "vendor_name": string,
  "total_amount": number,
  "currency": string,
  "line_items": [
    { "description": string, "quantity": number, "unit_price": number, "total": number }
  ]
}

If a field is not present in the document, use null.

Document text:
"""
{{pdf_text}}
"""

This pattern — a strict schema plus a "return only JSON" instruction — is the single biggest lever for reliability. If you need guaranteed structural validity (not just well-formatted JSON), combine this with Claude's tool use feature, which lets you define a schema the model must conform to when it responds. That approach is covered in detail in the /docs/tools documentation.

Step 3: Send the Request Through the API

Once you have the extracted text and the prompt, the request itself is straightforward. Here's an example using SubToAPI, which exposes your Claude access as a standard HTTPS API with an application key (sub_live_...):

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet-latest",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Extract invoice fields as JSON: ... [pdf_text] ..."
      }
    ]
  }'

The response comes back as plain JSON you can parse directly in your backend. If you're processing large batches of PDFs — e.g., a nightly job ingesting hundreds of invoices — you'll also want visibility into token usage per document, since cost scales with document length. SubToAPI's dashboard tracks usage per API key, which is useful if different document types (contracts vs. receipts) run through separate keys for cost attribution. See /docs/messages for the full request reference.

Handling Multi-Page and Long Documents

Long contracts or multi-page statements can exceed what you want to send in a single call, or exceed context limits for very large files. Two practical strategies:

  1. Chunk by logical section. Split the PDF by page or by detected section headers, extract each chunk separately, then merge the results in your application logic.
  2. Two-pass extraction. First pass: ask Claude to identify which pages contain the data you need (e.g., "which page has the line-item table?"). Second pass: extract only from those pages. This reduces token usage and improves accuracy by narrowing the model's focus.

For documents with repeating structure (e.g., a 50-page statement with the same table format per page), process page-by-page and concatenate the JSON arrays rather than sending the whole document in one prompt. This also makes it easier to isolate and retry a single failed page instead of reprocessing everything.

Validating Output

Even with a strict schema, always validate the returned JSON before trusting it downstream:

This validation layer is what turns "AI extraction that mostly works" into a production-grade pipeline you can trust for financial or legal documents.

Getting Started

If you want to move from testing prompts manually to running this as a real backend process, you need an API key, not just chat access. SubToAPI turns your Claude subscription into an API you can call from a script, cron job, or server — with streaming, usage metadata, and team seats included. Plans start at Solo (€9), Team (€19/seat), and Scale (€49/seat), with a free trial at /signup. Full endpoint docs are at /docs, and a five-minute setup walkthrough is at /docs/quickstart.

Questions

Can Claude read PDF files directly, or do I need to extract text first? Claude works with text input, so for most workflows you extract the text layer from the PDF (or run OCR on scanned pages) before sending it in the prompt. This gives you more control over chunking and preprocessing than passing raw binary files.

How do I make sure Claude returns valid JSON every time? Give it a strict schema in the prompt, explicitly instruct it to return only JSON with no extra text, and consider using Claude's tool use feature for schema-enforced output. Always validate the parsed result before using it downstream.

Is Claude reliable enough for financial or legal document extraction? It's very capable, but treat it as a first-pass extractor, not a final source of truth. Add validation checks (sum totals, required fields, format checks) and route flagged documents to human review before committing data to production systems.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →