Contract review is a natural fit for Claude's citations feature: answers grounded in the source document, with machine-verifiable pointers to the passages that support each claim. But the precision of those pointers is set by decisions you make at ingestion time — how you split contracts into chunks, and which document type you use to present them. This article works through those decisions for legal-document workloads. (Standard disclaimer: this is engineering guidance, not legal advice, and an AI reviewer assists human review rather than replacing it.)
Chunk by clause, not by token count
Generic RAG pipelines split text into fixed-size chunks — 300 tokens, some overlap — because prose has no reliable structure. Contracts do: numbered sections and clauses are the units lawyers reason about, negotiate over, and cite in disputes. Splitting on clause boundaries instead of token counts means every retrieved chunk is a complete obligation or definition rather than half of one, and every citation lands on a unit that means something in an audit. The general trade-offs of chunk sizing are covered in the RAG chunking pattern; contracts are the easy case, because the document tells you where to cut.
Why custom content documents fit clause-level attribution
Claude's citations support three document types. Plain text documents are sentence-chunked by the API and cited by character range (char_location); PDFs are cited by page range (page_location); and custom content documents use your content blocks as-is, cited by 0-indexed block range (content_block_location). The official docs' own RAG guidance points this way: use custom content documents when you want to control citation granularity yourself. Make each clause one text block, and every citation Claude returns is, by construction, a clause reference:
doc = {
"type": "document",
"source": {"type": "content", "content": [
{"type": "text", "text": "8.1 Either party may terminate for material breach..."},
{"type": "text", "text": "8.2 Customer may terminate for convenience on 30 days notice..."},
{"type": "text", "text": "8.3 Sections 5, 9, and 12 survive termination..."},
]},
"title": "MSA-2026-041 §8 Termination",
"context": '{"counterparty": "Acme Corp", "effective": "2026-01-15"}',
"citations": {"enabled": True},
"cache_control": {"type": "ephemeral"},
}
The context field carries metadata (the docs recommend it over the length-limited title); it is passed to the model but never cited. For audit trails this structure is the payoff: a content_block_location citation with start_block_index: 1 is durably "clause 8.2" in your records — no character-offset arithmetic, no page-number ambiguity across PDF renderings. Log the citation objects alongside each answer and you have a reviewable trail of which clause supported which conclusion. Two constraints to design around: citations are all-or-nothing across the documents in a request, and citation-enabled documents cannot be combined with structured outputs — that returns a 400 error, so emit findings as text plus citations rather than a JSON schema.
Prompt caching: the economics of asking one corpus many questions
Contract review is repetitive by nature: the same playbook of questions — termination, liability caps, indemnification, data protection — runs against every agreement, and a negotiation asks many questions of one document. That access pattern is exactly what prompt caching rewards. Mark the document blocks with cache_control (as above — source documents are cacheable even with citations enabled; the citation outputs themselves are not): the first request writes the cache at 1.25x the base input price for a 5-minute TTL (2x for 1-hour), and every subsequent question reads it at 0.1x — a 90% discount on the corpus portion of each query. The 5-minute cache pays for itself on the second question. Minimums are generous for this use case — e.g. 1,024 tokens on Claude Opus 4.8, and a contract corpus clears that trivially. Keep the corpus prefix byte-stable across requests (same documents, same order) so the cache actually hits, and put questions at the end of the prompt — which also matches the long-context guidance of data first, query last.
cited_text does not count toward output tokens.Retrieval and platform notes
For corpora too large to send whole, the retrieval index sits in front: Anthropic's embeddings guidance points to Voyage AI, which offers a legal-domain model, voyage-law-2 (16K-token context) — see Voyage embeddings — with retrieved clauses passed as custom content documents or search_result blocks. Platform-wise this design travels well: citations are GA on the Claude API, Claude Platform on AWS, Bedrock, and Vertex AI, and Microsoft's Foundry docs list citations as a supported capability. One caveat: scanned contracts without extractable text cannot be cited — OCR them first. And as always with legal workloads, your deployment inherits your cloud provider's compliance posture — confirm specifics with your provider.
Where to go next
See controlling citation granularity with custom content for the document-type mechanics in depth, and Files API with citations for storing frequently reviewed documents once instead of resending them.