Claude Seekho

Vision, PDFs, Files, Citations and Structured Outputs

Claude understands images and PDFs along with text. To make output reliable there are structured outputs (JSON schema), and for verifiable answers there are citations.

8.1 Image and PDF input

import base64
pdf = base64.standard_b64encode(open("invoice.pdf", "rb").read()).decode()

r = client.messages.create(
    model="claude-opus-5-5", max_tokens=4000,
    messages=[{"role": "user", "content": [
        {"type": "document",
         "source": {"type": "base64", "media_type": "application/pdf", "data": pdf}},
        {"type": "image",
         "source": {"type": "url", "url": "https://example.com/chart.png"}},
        {"type": "text", "text": "Tell me the invoice total and the chart trend."},
    ]}],
)
  • Images: JPEG, PNG, GIF, WebP. You can provide them as base64, a URL or through the Files API. Put the image before the text.
  • PDF: both the text and an image of every page are understood (tables and charts too). Limit: 32 MB request, 600 pages (100 on 200K-context models).
  • Claude does not generate images — it can create visuals through SVG/HTML/code.

8.2 Files API

Instead of uploading the same file again and again, upload it once, get a file_id, then reference it in requests.

f = client.files.upload(file=open("policy.pdf", "rb"))
r = client.messages.create(model="claude-opus-5-5", max_tokens=4000, messages=[{
    "role": "user", "content": [
        {"type": "document", "source": {"type": "file", "file_id": f.id}},
        {"type": "text", "text": "Summarize the leave policy"}]}])

8.3 Citations

Set citations: {enabled: true} on the document block. The response text blocks then carry a citations array with cited_text and a location (page number for PDFs) — the user can verify where the answer came from.

8.4 Structured outputs

When a program has to parse the output, provide a JSON schema. The response is guaranteed to be schema-valid.

from pydantic import BaseModel

class Lead(BaseModel):
    name: str
    email: str
    plan: str

r = client.messages.parse(
    model="claude-opus-5-5", max_tokens=2000,
    messages=[{"role": "user", "content": "Extract: Amit (amit@x.com) wants the Enterprise plan"}],
    output_format=Lead,
)
print(r.parsed_output.email)      # validated Pydantic object