This session started with a simple question — did I use up my Claude token budget? — and turned into a full audit of how Claude actually charges for things, plus a structural fix to a Python script along the way.
The project is a family history research tool: a Python script that takes scanned Chinese PDF documents and converts each page into markdown using Claude's vision API. Each page is rendered as a PNG, base64-encoded, and sent to Claude with a Chinese OCR prompt. The response comes back as structured markdown, one page at a time.
We walked through every parameter in the core client.messages.create call: model, max_tokens, cache_control, and the multimodal messages array that carries both the image and the instruction text together in one request.
The script had cache_control={"type": "ephemeral"} at the top level of the API call — the auto-cache shortcut that targets the last cacheable block in the request. The problem: the image came last in the content array. Since the image changes every page, its bytes became part of the cache key. Every single page missed the cache.
The fix was two steps:
"cache_control": {"type": "ephemeral"} directly to the text block itselfNow the cache key covers only the stable text prompt. The changing image lives after the breakpoint and doesn't affect it.
One honest caveat: claude-sonnet-4-6 requires a minimum of 2048 tokens before a breakpoint to actually write to cache. This prompt is about 150 tokens, so caching won't trigger in practice. The fix is structurally correct and ready for the day the prompt grows.
The token budget question opened into a clearer map of how Claude charges for things. There are three separate systems, and they do not share budgets:
Anthropic API billing — per token, per call. Every client.messages.create() in the Python script hits this. Completely independent of any subscription. Charged to your API account.
Claude Pro subscription — $20/month flat rate. Covers claude.ai web chat and Claude Code in VS Code when signed in with your claude.ai account. Has a monthly message limit, not unlimited.
Claude Code in VS Code — the one people miss. Depending on how it's configured, it either draws from your Pro subscription or bills per token to the same API account as your Python script. Every file snippet auto-included in a prompt counts toward whichever bucket you're in.
We confirmed the VS Code extension was authenticated and working with a quick test message. The context chip — </> pdf_to_markdown.py#40-... — showed the editor automatically including the selected code as context.
Edited and refined with assistance from Claude Code.