You need one clause out of an eighty-page contract
Search the result instead of reading it: excerpts come back with the page they fall on, and reading the pages around them is free.
Somebody asks what the termination terms are. The contract is eighty pages, the answer is two paragraphs, and nobody knows which page they are on.
The two ways to get there are both bad. Read the whole thing into the conversation and you have spent about twenty thousand tokens to use two hundred words, and the other seventy-nine pages stay in context degrading everything that follows. Guess a page range and you are betting on where a clause lives in a document you have not read.
What you want is the search you would do in a PDF viewer: type the word, get the hits with their page numbers, read around the ones that matter. That is the operation, and it is missing from every naive pipeline.
On a digital PDF, text search works and is not the hard part. On a scanned contract it finds nothing, because there is no text to search: the pages are pictures, and the empty result looks exactly like a document that does not mention termination. That is the wrong answer arriving with confidence.
Even once the characters are recognised, extraction hands back one flat string. The page numbers are gone. You can find the word and still not be able to say where it is, and a clause without a page reference is not something anyone can check against the paper copy.
So the local path either searches nothing, or searches something that has lost the one piece of metadata that makes the answer usable. And the workaround, reading everything so the model can find it, is precisely the cost you were trying to avoid.
Read once, then search the result. find is a case-insensitive text search and returns excerpts with the page each one falls on. Every result call is free.
upload(filename="contract.pdf", content_type="application/pdf")
-> key, upload_url
curl -T contract.pdf "<upload_url>"
read(key="<key>")
-> handle, engine, structure, tokens_if_inlined
result(handle="<handle>", find="termination")
-> matches, match_count, matches_omitted
result(handle="<handle>", pages="12-14")
-> the pages around the match, in full
result(handle="<handle>", find="notice period")
-> another search, same handle, still freeYou pay once, for the read. balanced costs 0.007 EUR per page, about 0.56 EUR for eighty pages, and nothing at all when the PDF already carries its own text and can be extracted locally. exact costs 0.016 EUR per page and goes straight to an engine, which is what you want on a scan of a signed copy.
Searching is free and so is paging. Ten searches and four page ranges cost the same as one: result is never charged, because the work was already paid for when the document was read.
Reading the same contract twice costs once. The file is recognised by its contents rather than its name, so the second call returns the first result and charges nothing, even if somebody renamed it in the meantime.
findis a text search, case-insensitive and literal. It matches words, not meanings: a clause that never uses the word you searched for will not come back.- A search that hits hundreds of times returns the first excerpts and reports the rest in
matches_omitted, rather than flooding your context. Narrow the term or read the pages. - Page numbers are the pages of the file. If the printed document is numbered differently, the two will not agree.
- Email files (EML, MSG) and ebooks (EPUB) are read by no engine. Extract the text or convert to PDF first.
Without markup
This page in markdown: /problems/find-one-clause-in-a-long-contract.md. All 20 of them in one file: /llms-full.txt.