← Blog

Claude API Token Usage Optimization Techniques

2026-10-25 · 5 min read · SubToAPI Team

Token usage drives both cost and latency on the Claude API, so optimizing it means fewer tokens sent per request, fewer tokens wasted on repeated context, and shorter, more targeted completions. The techniques below are the ones that actually move the needle: trimming system prompts, managing conversation history intelligently, using prompt caching, capping output length, and picking the right model for each task.

If you're seeing high bills or slow responses, the fix is rarely "switch models and hope." It's a combination of measuring where tokens go, cutting the obvious waste, and restructuring how you send context on every request. Here's how to do each.

Measure before you optimize

You can't optimize what you don't measure. Every Claude API response includes a usage object with input_tokens and output_tokens. Log this on every call, broken down by endpoint or feature, before you change anything.

curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet-20241022",
    "max_tokens": 500,
    "messages": [{"role": "user", "content": "Summarize this ticket: ..."}]
  }'

The response's usage.input_tokens will often surprise you — system prompts and conversation history frequently outweigh the actual user message by 5-10x. If you're running this through SubToAPI, the same usage metadata is returned per call and aggregated in the dashboard, so you can see per-key and per-team consumption without building your own logging pipeline. See /docs/messages for the full response shape.

Trim your system prompt

System prompts accumulate cruft over time: old instructions nobody removed, redundant examples, formatting rules repeated three different ways. Audit it like you'd audit dead code.

A system prompt that's 2,000 tokens instead of 500 costs you 1,500 extra input tokens on every single request, not just once. At scale that's the single biggest lever most teams ignore.

Don't resend full conversation history

If you're building a chat-style product, the naive approach — append every message and resend the whole array every turn — scales token cost linearly with conversation length. A few fixes:

Sliding window: only send the last N turns, dropping older ones once they're no longer relevant to the current question.

Summarization checkpoints: every K turns, replace the oldest messages with a short model-generated summary of what was discussed. This keeps continuity without keeping every token.

Reference by ID, not content: if the conversation touches on a document or dataset, store it once and reference it by ID in your own system, rather than re-pasting it into every message.

function buildMessages(history, maxTurns = 8) {
  // keep only the most recent turns, summarize the rest
  if (history.length <= maxTurns) return history;
  const recent = history.slice(-maxTurns);
  const summary = {
    role: "user",
    content: `[Earlier conversation summary]: ${summarizeOlder(history.slice(0, -maxTurns))}`
  };
  return [summary, ...recent];
}

Use prompt caching for repeated context

If the same large block of context — a system prompt, a document, a tool schema — is sent on every request, prompt caching avoids reprocessing it each time. Anthropic's API supports cache control on message blocks, and the cached portion is billed at a reduced rate on subsequent calls within the cache window. This is the highest-leverage technique for any workload with a stable, large context (RAG pipelines, document Q&A, coding assistants with a big system prompt).

Structure your request so the static content comes first and is marked as cacheable, with the variable user input appended after. The exact gains depend on how much of your prompt is reusable, but for document-heavy workloads it's common to cut repeated-context costs dramatically on follow-up turns.

Cap output tokens deliberately

max_tokens isn't just a safety limit — it's a cost control. If your use case needs a short classification label or a JSON object with five fields, there's no reason to allow a 4,000-token completion. Set max_tokens tight to the expected output shape:

{
  "model": "claude-3-5-sonnet-20241022",
  "max_tokens": 150,
  "messages": [...]
}

For structured outputs, pair this with explicit formatting instructions ("respond with only the JSON object, no explanation") so the model doesn't pad its answer with preamble you're paying for and then discarding.

Match the model to the task

Not every call needs your most capable model. Classification, extraction, routing, and short rewrites often work fine on a smaller, cheaper model, reserving the larger one for genuinely hard reasoning tasks. Splitting your pipeline by task complexity — a cheap model for triage, an expensive one only when triage flags it as complex — can cut average per-request token cost significantly without touching quality on the tasks that matter.

Batch and deduplicate requests

If your application sends near-identical requests (e.g., the same question asked by multiple users within a short window, or repeated validation checks), add an application-level cache keyed on a hash of the prompt. Skip the API call entirely for exact or near-duplicate inputs you've already answered recently.

How SubToAPI fits in

None of these techniques require SubToAPI, but if you're already routing Claude traffic through it, the per-key usage metadata makes it much easier to find where tokens are going — which team, which feature, which endpoint. You get clean sub_live_... keys for each app or environment, streaming support, and tool use, with usage visible per seat in one dashboard rather than scattered across logs. Check /docs/quickstart to get a key issued in a few minutes, or compare plans at /pricing if you're consolidating multiple Claude integrations behind one API layer.

Questions

Does prompt caching actually reduce input token cost? Yes — cached portions of a prompt are billed at a reduced rate on subsequent requests within the cache lifetime, which matters most when you resend large static context (system prompts, documents, schemas) on every call.

Is it better to summarize conversation history or just truncate it? Truncating is cheaper computationally but loses context; summarizing costs a small extra model call but preserves continuity in long conversations. Use truncation for short-lived sessions and summarization for anything users expect to reference later.

Will lowering max_tokens hurt output quality? Not if you set it to match the expected output shape. A tight max_tokens on a classification or JSON-extraction task just prevents padded, rambling completions — it only hurts quality if you cut off a response that genuinely needed more room to reason or write.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →