Analyzing contracts with AI: where to start
A 40-page contract can go through the API in a minute, but it pays to know the cost upfront and pick the right model for a scan versus clean text.
4 min · · Updated · бизнес · договоры
"Find the risky clauses in this contract" sounds simple until you run into two things: contracts often arrive as scans rather than clean text, and their length, multiplied by hundreds of documents a month, quickly turns into a real line item. Here's how to build this on the API without tripping over either problem.
A text contract is the easy case
If the contract is already text (a DOCX or a PDF with a text layer, extracted to plain text), the task comes down to one call with a detailed system prompt:
curl https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_your_key" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 4000,
"system": "You are a contract lawyer. Find clauses on penalties, unilateral termination, auto-renewal, and liability limitation. For each, give the quote, the risk to the client party, and a recommendation.",
"messages": [{"role": "user", "content": "'"$(cat contract.txt | jq -Rs .)"'"}]
}'The example uses claude-opus-5-5: legal analysis needs careful multi-step reasoning through the text (extended thinking), not a fast answer. On Zukko it costs the same as claude-sonnet-5 ($0.30/$0.30 per 1M input/output tokens), so pick between them by quality on your own contracts — test both on your tasks. The 1,000,000-token context covers even a lengthy master agreement with exhibits in a single request.
A scanned contract — working through vision
If the contract arrives as a photo or a scan with no text layer — common with old paper archives or hand-signed amendments — the Claude and GPT models accept images (GLM has no vision), so a separate OCR step isn't required; pages can go in directly:
import requests, base64
with open("contract_page_1.jpg", "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
resp = requests.post(
"https://api.zukko.pro/v1/messages",
headers={
"Authorization": "Bearer fetch_your_key",
"anthropic-version": "2023-06-01",
},
json={
"model": "claude-opus-5-5",
"max_tokens": 4000,For a multi-page scan, it makes more sense to send pages together in one message, several image blocks in a row, rather than one request per page — cheaper on overhead, and the model sees the whole document without losing context between sheets.
Estimating cost before a bulk run
If you're planning to run an archive of hundreds of contracts at once, estimate cost on a sample first. The free token count only works on text input, not images, so for scans it's more practical to take 5-10 representative documents, run them, and read the X-Zukko-Cost-Micros header from each response:
total_micros = 0
for path in sample_files:
resp = send_contract(path)
total_micros += int(resp.headers.get("X-Zukko-Cost-Micros", 0))
avg_cost_usd = (total_micros / len(sample_files)) / 1_000_000
print(f"Average cost per contract: ${avg_cost_usd:.4f}")Multiplying the average by the size of the archive gives a clear number before running the whole batch.
A two-stage pipeline for large volumes
Not every contract in an archive needs in-depth analysis. A practical setup: a fast, cheap first pass on gpt-5.6-luna ($0.10/$0.10 per 1M tokens; for text contracts glm-5.3-flash at $0.04/$0.04 works too) classifies each document — "standard supply agreement," "non-standard terms," "needs a lawyer" — and only the "non-standard" bucket goes to claude-opus-5-5 ($0.30/$0.30) for detailed analysis. That noticeably cuts total archive-processing cost — a run on your own sample will show by how much; check the first-pass classification quality on your documents too.
Idempotency on reprocessing
Contract analysis sometimes gets re-run — say, if the first pass's result was lost to a storage failure. An Idempotency-Key built from the contract file's hash guarantees a rerun doesn't charge twice for the same document:
IDEMPOTENCY_KEY="contract-$(sha256sum contract.pdf | cut -d' ' -f1)"
curl https://api.zukko.pro/v1/messages \
-H "Authorization: Bearer fetch_your_key" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d @payload.jsonKey limits for a legal team
If several lawyers share access to contract analysis through one tool, it's worth issuing a separate key with a monthly spend cap — detailed legal analysis of long contracts burns far more tokens than routine chat calls, and without a cap a forgotten loop in a script can process the same archive several times overnight. The cap and the list of allowed models are set on the key's page in the dashboard (https://zukko.pro/app/api-keys).
Errors specific to this task
A 400 unrelated to the model usually means an image exceeds the size limit — compress a scan before sending it rather than uploading a raw 20-megapixel original. 402 means the balance is empty, and in a legal context that's especially unwelcome — if a batch is scheduled overnight, check the balance via GET /v1/balance before the batch starts rather than after processing stalls halfway through the archive. A response cutting off mid-analysis almost always means max_tokens is set too low for a thorough breakdown — for a detailed legal opinion, budget 4,000-6,000 output tokens rather than leaving the default.
Bottom line: claude-opus-5-5 (or claude-sonnet-5, if it holds up on your tasks) for the hard analysis, vision directly on scans with no separate OCR step, a two-stage filter for large archives, and cost estimation on a sample before the full run — with that, contract analysis can run at scale without turning a pilot into a surprise invoice.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- AI for testers: test cases, checklists and bug reportsHow a QA engineer can use a model for test cases, checklists and bug reports, check coverage, and avoid requirements the model made up.
- Anonymizing data before sending it to a neural network: a practical wayYou do not have to send personal data to a model for it to process a document. How to replace it with labels, restore it in the answer and check that nothing leaked.
- A neural network for HR: job posts, candidate emails and resume reviewA model can draft job posts and emails and do a first-pass resume review. What to hand over, how to treat candidates' personal data and how to prevent biased decisions.
- An AI agent for 1C: which tasks to automate and howAn agent around 1C answers questions from data, drafts documents and looks for anomalies. We cover the scenarios, the HTTP-service architecture and safety measures.