---
title: "Estimate input tokens for an Anthropic Messages request"
method: POST
path: "/v1/messages/count_tokens"
tags: ["Anthropic"]
---

# Estimate input tokens for an Anthropic Messages request

`POST /v1/messages/count_tokens`

## Request

- Base URL: `http://localhost:9998`
- URL: `http://localhost:9998/v1/messages/count_tokens`
- Auth: HTTP bearer

Heuristic input-token estimator. Accepts the same shape as
`/v1/messages` minus `max_tokens` (optional here per the
Anthropic spec). Returns `{"input_tokens": N}`.

v1 is a heuristic (4 chars/token + per-message overhead +
per-image fixed cost), not a real BPE tokenizer call. Targets
±10 % accuracy across representative shapes. Sufficient for
Claude Code's advisory context-window display.

Auth identical to `/v1/messages`: `Authorization: Bearer tp_<64 hex>`,
validated by the unified middleware before dispatch.

## Request body

- AnthropicCountTokensRequest: Token-counting request. Same field semantics as `AnthropicMessagesRequest` EXCEPT `max_tokens` is optional (token counting doesn't require a generation budget) and `stream` is irrelevant. Defined inline rather than via `allOf` because OpenAPI's allOf cannot subtract a `required` field from its parent — code generators would otherwise demand `max_tokens` here, contradicting the server's actual contract.
  - `model` string, required
  - `max_tokens` integer: Optional here. If present, must still be a positive integer ≤ 100000.
  - `messages` AnthropicInputMessage[], required
    - `role` 'user' | 'assistant', required
    - `content` union, required
      - string
      - AnthropicContentBlock[]
        - union
          - AnthropicTextBlock
            - `type` 'text', required
            - `text` string, required
          - AnthropicImageBlock: Image content block (Phase 9). Translated to OpenAI's `image_url` content part on dispatch — base64 sources serialize as `data:<media_type>;base64,<data>` URLs; URL sources pass through verbatim.
            - `type` 'image', required
            - `source` union, required
              - …
          - AnthropicToolUseBlock
            - `type` 'tool_use', required
            - `id` string, required
            - `name` string, required
            - `input` object, required
          - AnthropicToolResultBlock
            - `type` 'tool_result', required
            - `tool_use_id` string, required
            - `content` union, required
              - …
            - `is_error` boolean
  - `system` union
    - string
    - AnthropicTextBlock[]
      - `type` 'text', required
      - `text` string, required
  - `tools` AnthropicToolDefinition[]
    - `name` string, required
    - `description` string
    - `input_schema` object: JSON Schema (canonical safe-subset).
  - `tool_choice` union
    - object
      - `type` 'auto', required
    - object
      - `type` 'any', required
    - object
      - `type` 'tool', required
      - `name` string, required
  - `temperature` number
  - `top_p` number
  - `top_k` integer
  - `stop_sequences` string[]
  - `metadata` object

## Response `200`

Estimated input token count

- AnthropicCountTokensResponse
  - `input_tokens` integer, required: Heuristic estimate (4 chars/token + per-message + per-image cost).

## Other responses

- `400`: Validation failure (Anthropic envelope)
- `401`: Authentication failed
- `413`: Request body exceeds 10 MB

---

[API](https://skmtc.dev/modelpiper/apis/toolpiper-api.md) · [All operations](https://skmtc.dev/modelpiper/apis/toolpiper-api/llms.txt) · [OpenAPI document](https://skmtc.dev/modelpiper/apis/toolpiper-api/revisions/6722bf56385c?raw)
