Skip to content

05 - Files API, Citations, and PDFs

Three closely related features that together let Claude work with documents and produce grounded, attributed responses.


Files API

The Files API lets you upload binary content (PDFs, images, JSON, etc.) once and reference it by ID across many requests.

Why

  • Avoid re-uploading the same file on every request
  • Keep request payloads small and fast
  • Reuse uploaded content across batch requests

Upload

file = client.files.create(
    file=open("contract.pdf", "rb"),
    purpose="user_data",  # purpose semantics per current docs
)
print(file.id)  # file_...

Reference in Messages

client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "document", "source": {"type": "file", "file_id": file.id}},
                {"type": "text", "text": "Summarize this contract."},
            ],
        }
    ],
)

Lifecycle

  • Files have storage TTL per your account (check current docs)
  • Delete via client.files.delete(file.id) when no longer needed
  • Track file IDs in your own datastore for reuse

Limits

  • Maximum file size per request and per file (check docs)
  • Supported types: PDFs, images (PNG/JPEG/GIF/WebP), text, JSON, more
  • Some types require beta headers

Vision (Image Input)

Pass images via base64, URL, or file_id:

{
    "type": "image",
    "source": {
        "type": "base64",
        "media_type": "image/png",
        "data": base64_string,
    },
}

URL form:

{"type": "image", "source": {"type": "url", "url": "https://..."}}

File ID form:

{"type": "image", "source": {"type": "file", "file_id": file.id}}

Use cases:

  • OCR replacement (Claude reads and reasons about image content)
  • UI screenshot analysis
  • Chart and diagram interpretation
  • Visual classification

Tips:

  • Resize very large images before upload to control token count
  • Image tokens are billed; a 1080p image costs roughly thousands of tokens depending on detail level

PDF Support

PDFs are sent as document content blocks. Claude reads both text and visual layout (charts, tables, diagrams).

{
    "type": "document",
    "source": {
        "type": "base64",
        "media_type": "application/pdf",
        "data": base64_pdf,
    },
}

Or via file_id (preferred for reuse):

{"type": "document", "source": {"type": "file", "file_id": file.id}}

Use cases:

  • Contract analysis
  • Research paper summarization
  • Financial filing extraction
  • Compliance review

Tips:

  • Large PDFs use a lot of tokens; check count_tokens first
  • Combine with prompt caching when the same PDF is referenced many times
  • Combine with citations (next section) for attribution

Citations

Citations let Claude attribute spans of its response to specific spans of source documents.

Enabling

Include citations: {enabled: true} on document content blocks:

{
    "type": "document",
    "source": {"type": "file", "file_id": file.id},
    "citations": {"enabled": true},
    "title": "Acme 2025 Annual Report",
    "context": "Filed with SEC on 2025-12-31",
}

Response Shape

Claude's text content blocks include a citations array tied to spans:

{
  "type": "text",
  "text": "Revenue grew 23% in Q4...",
  "citations": [
    {
      "type": "page_location",
      "cited_text": "Q4 revenue rose to $1.2B from $980M...",
      "document_index": 0,
      "document_title": "Acme 2025 Annual Report",
      "start_page_number": 14,
      "end_page_number": 14
    }
  ]
}

Citation types vary by document type (page_location for PDFs, char_location for text).

When to Use

  • Compliance and audit use cases
  • Customer-facing RAG that must show "sources"
  • Research assistants
  • Any workload where the user must verify the source

Quality Notes

Citations are generated by Claude based on actual evidence in the documents. They are not perfectly precise but are far more reliable than asking Claude to fabricate source markers in prose.

Tips

  • Provide title and context per document so Claude can disambiguate
  • Order documents by relevance when possible
  • Render citations as inline footnotes or hover tooltips for best UX
  • Log citations alongside responses for compliance

Composition Pattern

A typical RAG-with-attribution flow:

# 1. Upload documents once
docs = [client.files.create(file=open(p, "rb"), purpose="user_data") for p in paths]

# 2. Cache the static system prompt
system = [
    {
        "type": "text",
        "text": "You are a research assistant. Always cite your sources.",
        "cache_control": {"type": "ephemeral"},
    }
]

# 3. Send query with documents and citations enabled
content = []
for d in docs:
    content.append({
        "type": "document",
        "source": {"type": "file", "file_id": d.id},
        "citations": {"enabled": True},
    })
content.append({"type": "text", "text": user_question})

resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    system=system,
    messages=[{"role": "user", "content": content}],
)

# 4. Render text with citation spans
for block in resp.content:
    if block.type == "text":
        render(block.text, block.citations)

Common Pitfalls

  • Re-uploading the same file every request (use file_id)
  • Forgetting to enable citations explicitly
  • Storing PDFs as base64 in memory and forgetting to free
  • Not measuring per-image token cost
  • Using citations in the system prompt instead of document blocks

Exam Focus

  • Files API upload-once, reference-by-id pattern
  • document content block shape
  • Enabling citations and reading the response
  • Image input variants (base64, URL, file_id)
  • Combining files + caching + citations for production RAG