Skip to content

Cost and FinOpsGuide

How to count tokens before you call the API: OpenAI, Claude, Gemini

A local tokenizer gets plain text right and almost everything else wrong: tools, images, PDFs, message formatting, and the tokenizer change between model generations. Each major provider now has a counting endpoint. Here is how to use them, and what they still cannot tell you.

By INFRO Editorial

Published

6 min read

A dark ground with an amber gauge needle resting short of its limit, small glass segments around the dial representing counted tokens

In short

To count tokens before a request, use the provider's counting endpoint with the exact payload you will send: OpenAI's POST /v1/responses/input_tokens, Anthropic's POST /v1/messages/count_tokens (free, rate-limited separately) or Gemini's countTokens. Local tokenizers such as tiktoken count plain text well but miss formatting tokens, tools, images and files. No endpoint can count output, so a cost estimate is the input count times the input rate plus max_tokens times the output rate as the worst case.

Key takeaways

  • Count with the provider's own endpoint and the exact payload you will send; local tokenizers miss formatting, tool, image and file tokens.
  • OpenAI: POST /v1/responses/input_tokens. Anthropic: POST /v1/messages/count_tokens, free with its own rate limit. Gemini: countTokens.
  • Counts are per model: Claude 4.7 and later produce about 30% more tokens than earlier Claude models for the same text.
  • No endpoint counts output. Bound it with max_tokens and price the worst case.
  • Use local counting for rough sizing in hot paths and endpoint counting where the number decides something: a budget, a route or a context trim.

How do you count tokens before calling an LLM API? Send the exact request payload to the provider's counting endpoint: POST /v1/responses/input_tokens on OpenAI, POST /v1/messages/count_tokens on Anthropic, or countTokens on Gemini. Each returns the input token count for that model. A local tokenizer such as tiktoken is faster and free, but it only counts plain text correctly; tools, images, files and the formatting around messages are where local counts go wrong.

This guide covers the three providers' methods, what each counts, and how to turn a count into a cost bound you can act on.

Why count before the call

Four decisions need a token count before the provider sees the request:

  1. Cost. Input count times input rate, plus the output limit times the output rate, is the most a request can cost. That is what a budget check needs.
  2. Context fit. A prompt that will not fit the model's window should be trimmed or summarised before it is sent, not after the 400.
  3. Pricing thresholds. Some rates change with prompt length: OpenAI above 272K input tokens, Claude Haiku 5.5 above 100,000, Gemini 3.1 Pro above 200K. A request just over the line is re-priced as a whole.
  4. Routing. Small prompts can go to a small model and very large ones to a model with the window for them.

The three providers' methods

ProviderMethodCountsCost to callNotes
OpenAIPOST /v1/responses/input_tokensText, messages, images, files (PDF), tools, formattingNot statedSame payload as a Responses request
AnthropicPOST /v1/messages/count_tokensSystem prompt, messages, tools, base64 images and PDFs, thinkingFree; 5,000–20,000 RPM by tierRefuses server tools and URL-sourced media
Googlemodels.count_tokens / countTokensContents, system instructions, tool definitionsNot statedReturns input total only
Localtiktoken and similarPlain textFreeNo images, files, tools or message formatting
Token counting methods as each provider documents them, 2026-10-20.

OpenAI

OpenAI's counting endpoint accepts the same input as responses.create and returns {"object": "response.input_tokens", "input_tokens": N}. Its guide names exactly where local counting fails: images and files ("estimates like characters / 4 are inaccurate"), tool and schema definitions, and model-specific behaviour. It also notes that the count "includes formatting tokens used to represent request structure, such as message roles and boundaries"1.

count_openai.py
from openai import OpenAI

client = OpenAI()
count = client.responses.input_tokens.count(
    model="gpt-6-sol",
    instructions=open("system_prompt.txt").read(),
    input="Summarise the attached ticket thread.",
    tools=[{"type": "function", "name": "lookup_order", "parameters": {"type": "object", "properties": {}}}],
)
print(count.input_tokens)

For plain text in a hot path, tiktoken is OpenAI's open-source BPE tokenizer: tiktoken.encoding_for_model("gpt-4o") returns that model's encoding, and o200k_base and cl100k_base can be loaded by name2. Treat a local count as a lower bound for a chat request, because it does not see roles, tools or attachments.

Anthropic

Anthropic's endpoint takes the same body as a message request — system prompt, messages, tools, images and PDFs as base64, thinking settings — and returns input_tokens. It is free, rate-limited per minute by usage tier, and its limits are independent of message creation3. Three behaviours to know:

  • It is an estimate. Anthropic says the actual input tokens "might differ by a small amount", and that tokens it adds for system optimisations are not billed3.
  • It refuses some inputs. Server tools (web search, web fetch, code execution), the MCP connector and images or documents given by URL or file id return invalid_request_error. Count those requests from the usage of the real response instead.
  • It counts per model. Claude 4.7 and later, including the Fable family, use a tokenizer that produces roughly 30% more tokens for the same text. Anthropic's advice is to recount against the model you plan to use rather than reuse old counts3.
count_claude.sh
curl https://api.anthropic.com/v1/messages/count_tokens \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5-5",
    "system": "You are a support assistant.",
    "messages": [{"role": "user", "content": "Where is order 4471?"}]
  }'
# {"input_tokens": ...}

On a conversation with extended thinking, previous turns' thinking blocks count as input on models that keep them, and the current turn's thinking counts too3.

Google Gemini

Gemini's SDKs expose client.models.count_tokens (Python) and countTokens (JavaScript), which return the input total; Google recommends calling it before sending large inputs4. Its guide also gives fixed costs for media that are useful for estimates without a call:

  • Text: about 4 characters per token; 100 tokens is about 60 to 80 English words.
  • Images: 258 tokens up to 384 pixels on each side; larger images are tiled at 768 by 768, 258 tokens per tile.
  • Audio: 32 tokens per second.
  • System instructions and tool definitions count as input4.
count_gemini.py
from google import genai

client = genai.Client()
result = client.models.count_tokens(
    model="gemini-3.8-flash",
    contents="Summarise the attached ticket thread.",
)
print(result.total_tokens)

What no endpoint can count

Output. Generated tokens, including reasoning or thinking tokens, exist only after generation. OpenAI bills reasoning as output and reports it afterwards; Gemini's output price includes thinking tokens. The only pre-call control is the output limit: max_output_tokens or max_completion_tokens on OpenAI, max_tokens on Anthropic, maxOutputTokens on Gemini. Price the limit, not the expected length.

That gives a simple upper bound:

worst-case cost of one request
max_cost = input_tokens × input_rate + max_output_tokens × output_rate
# input_tokens from the counting endpoint, rates per token for the target model
# a cached prefix lowers the real cost; it never raises the bound above this

Counting across providers

A count is only meaningful for the model it was taken on. The same prompt can produce materially different counts on OpenAI, Anthropic and Google, and even between two generations of one vendor's models. Three consequences:

  • Do not compare rates without counts. A model with a lower rate per token can cost more per request if its tokenizer produces more tokens for your text. Compare cost per request on your own prompts.
  • Re-count on migration. Moving a workload between providers, or across Claude's 4.6-to-4.7 tokenizer change, changes the count before it changes the rate.
  • Keep counts per target. A gateway that may fail over from one provider to another should bound cost with the most expensive target in the chain.

Local or endpoint: which to use where

SituationUse
Hot path, plain text, rough sizingA local tokenizer, with a safety margin
A budget or spend-cap decisionThe provider's endpoint, or the real response's usage afterwards
Requests with images, PDFs or many toolsThe provider's endpoint
Requests near a pricing or context thresholdThe provider's endpoint
After the call, for accountingThe usage object of the response — never a re-count

Endpoint calls add latency, so where counting sits on the request path, cache counts for stable prefixes (system prompts, tool lists) and count only the changing part.

Counting with INFRO

INFRO's gateway needs a bound before every request it serves, because budgets are checked before the provider is called: it reserves a worst-case estimate from the prompt size and the request's output limit, admits the request only if that fits the room left, and records the provider-reported usage afterwards. You can ask for the same estimate yourself with POST /v1/estimates without sending the request. For Claude Code and other clients on INFRO's /v1/messages, POST /v1/messages/count_tokens asks the first Anthropic connection that serves the model, is free, and leaves no request row; with no such connection the answer is an estimate and the X-INFRO-Token-Count: estimated header says so.

Summary

Count where the number decides something, with the exact payload, on the exact model. Use local tokenizers only as a fast lower bound for plain text, bound output with an explicit limit, and treat the usage in each response as the figure of record.

Questions readers ask

How do I count tokens for GPT models?
For plain text, tiktoken gives a fast local count: tiktoken.encoding_for_model returns the encoding for a known model. For a full request with tools, images or files, call OpenAI's POST /v1/responses/input_tokens with the same payload you would send to the Responses API; it includes formatting tokens a local count misses.
Is Anthropic's token counting API free?
Yes. Anthropic says token counting is free to use, with requests-per-minute limits by usage tier (5,000 to 20,000) that are separate from message creation. The count is an estimate and can differ by a small amount from the tokens billed.
How many characters is a token?
Roughly four characters of English text, which Google gives as its rule of thumb for Gemini. It varies by language, by code versus prose, and by model: Anthropic says Claude 4.7 and later models produce about 30% more tokens for the same text than earlier Claude models.
Can I count output tokens before the request?
No. Output, including reasoning or thinking tokens, is only known after generation. Set max_tokens or max_output_tokens and treat that limit as the worst case when you estimate cost.

From the team that builds it

Where this shows up in INFRO

INFRO is a control plane in front of the provider accounts you already hold. The capabilities below are the parts of it this article touches, each with the documentation that defines its behaviour.

  • Cost estimates before a request

    Available with a plan

    Ask what a request would cost on your own provider account before you make it: per image with resolution and quality tiers, per second of video, per character of speech, per token of text.

    Read the documentation for Cost estimates before a request
  • Budgets and spend ceilings

    Available with a plan

    A hard cap per organization, project, member, and key, with alerts at your own thresholds.

    Read the documentation for Budgets and spend ceilings
  • Claude Code and Codex through INFRO

    Available with a plan

    Point Claude Code, the Claude Agent SDK, Codex or the OpenAI Agents SDK at INFRO by changing the base URL and the key. Anthropic's Messages API and OpenAI's Responses API, with routing, budgets refused before the call, guardrails and the request log applied as on every other request.

  • Usage and cost per request

    Available with a plan

    Every request records its model, latency, token or unit counts, and estimated provider cost, queryable by project and key.

    Read the documentation for Usage and cost per request

INFRO accounts are self-serve. Provider usage is billed to you by your providers; INFRO charges a software subscription and takes 0% of model spend. See plans.

Sources

Numbered in order of first citation. Each was opened and checked against the claim on the date shown.

  1. 1.Counting tokens (opens in a new tab) — OpenAI. Accessed Oct 20, 2026.
  2. 2.openai/tiktoken (opens in a new tab) — GitHub. Accessed Oct 20, 2026.
  3. 3.Token counting (opens in a new tab) — Anthropic. Accessed Oct 20, 2026.
  4. 4.Understand and count tokens (opens in a new tab) — Google. Accessed Oct 20, 2026.

About this article

Endpoint behaviour is taken from OpenAI's, Anthropic's and Google's own documentation and the tiktoken README, opened on 2026-10-20. Code samples follow those pages' examples. Nothing here was benchmarked. Written by the team that builds INFRO, whose gateway counts tokens for budget checks.

Last checked against its sources on . The next review is due by . No separate named reviewer is recorded for this article.

How articles are written, sourced and corrected is set out in the editorial standards.