Run big-document analysis in this order. Skipping ahead is what burns loops.

1. Upload once, reference by id. Send the PDF through the Files API and reference it by file_id in later calls instead of re-sending bytes. The PDF page cap is 600 pages per request, but only 100 when the request's context window is under 1M tokens, and the whole request payload (PDF plus everything else) must stay under 32 MB. Dense PDFs with tiny fonts, complex tables, or heavy graphics can fill the context window before the page limit, so plan to split them into sections.
2. Token-count before you send. Use the token counting endpoint on each chunk. It accepts the same inputs as message creation (system instructions, tools, images, PDFs) and returns the input token total. Send images and PDFs as base64 for counting: url and file sources are rejected with invalid_request_error, and so are server tools, so for those read the usage object on the real response instead. Treat the count as an estimate, it can differ slightly from actual usage.
3. Budget the window per chunk. For each chunk: chunk tokens plus your max_tokens output budget plus room for citations must fit the model's context window. If a chunk plus the output budget does not fit, split the chunk, do not shrink max_tokens and hope.
4. Enable citations on the document blocks. Set citations enabled on each document content block so the model returns exact cited passages with each claim. All active models support citations, and citations also work in streaming as citations_delta events inside content_block_delta. If you ask for a structured response format, add an explicit instruction to use citations inside that format, otherwise the model may drop them.
5. Cache the stable prefix. Put the unchanging parts (system instructions, document blocks) first and the per-question text last, then add cache_control with type ephemeral on the stable blocks. Use automatic caching (a single top-level cache_control field) for multi-turn chats where the prefix grows, or explicit breakpoints for precise control. Choose the 5-minute or 1-hour TTL that matches your call rhythm.
6. Verify the citations, not just the answer. Walk each citation's cited_text back to the source passage. If a citation points at text that does not exist in the document, your chunking cut a passage mid-sentence: widen the overlap and rerun that chunk only.