Count Tokens
Estimate how many input tokens an Anthropic Messages request would consume. No upstream inference is invoked, no charge is incurred, and it does not count against concurrency, but the API key validity and the account's balance / subscription status are still checked.
Protocol boundary
This is the Anthropic-style token counting endpoint. The request body matches /v1/messages. Anthropic-platform groups forward token counting upstream, OpenAI-platform groups use compatible counting, and Grok returns an estimate.
Endpoint
POST https://api.sakrylle.com/v1/messages/count_tokensHeaders
| Name | Required | Description |
|---|---|---|
Authorization | Yes | Bearer sk-xxxxxxxxxxxxxxxx |
Content-Type | Yes | application/json |
anthropic-version | No | e.g. 2023-06-01, matches Anthropic's official header |
Request body
The request body is identical to POST /v1/messages:
| Field | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Claude model ID, e.g. claude-haiku-4-5-20251001 |
messages | array | Yes | Full conversation message list |
system | string | array | No | System prompt |
tools | array | No | Tool definitions; tokens for these are included in the count |
tool_choice | object | No | Same as messages |
Inference-only fields (
temperature,top_p,stream,max_tokens, etc.) are accepted for parsing but do not affect the token count.
Example request
{
"model": "claude-haiku-4-5-20251001",
"system": "You are a concise assistant.",
"messages": [
{ "role": "user", "content": "Introduce yourself." }
]
}Example response
{
"input_tokens": 36
}The field name matches Anthropic's
/v1/messages/count_tokens. The gateway forwards the upstream account's response.
Errors
400 invalid_request_error— missingmodel, body is not JSON, or parse failure401 authentication_error— invalid API key403 billing_error— balance or subscription quota exhausted (still validated even though no charge applies)503 api_error— no upstream account is available
For the full table, see Errors.
Code samples
curl https://api.sakrylle.com/v1/messages/count_tokens \
-H "Authorization: Bearer sk-xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-haiku-4-5-20251001",
"messages": [
{"role": "user", "content": "Hello"}
]
}'from anthropic import Anthropic
client = Anthropic(
api_key="sk-xxxxxxxxxxxxxxxx",
base_url="https://api.sakrylle.com",
)
resp = client.messages.count_tokens(
model="claude-haiku-4-5-20251001",
messages=[{"role": "user", "content": "Hello"}],
)
print(resp.input_tokens)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: "sk-xxxxxxxxxxxxxxxx",
baseURL: "https://api.sakrylle.com",
});
const resp = await client.messages.countTokens({
model: "claude-haiku-4-5-20251001",
messages: [{ role: "user", content: "Hello" }],
});
console.log(resp.input_tokens);package main
import (
"bytes"
"fmt"
"io"
"net/http"
)
func main() {
body := []byte(`{
"model": "claude-haiku-4-5-20251001",
"messages": [{"role":"user","content":"Hello"}]
}`)
req, _ := http.NewRequest("POST",
"https://api.sakrylle.com/v1/messages/count_tokens",
bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer sk-xxxxxxxxxxxxxxxx")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("anthropic-version", "2023-06-01")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
}use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::new();
let resp: serde_json::Value = client
.post("https://api.sakrylle.com/v1/messages/count_tokens")
.bearer_auth("sk-xxxxxxxxxxxxxxxx")
.header("anthropic-version", "2023-06-01")
.json(&json!({
"model": "claude-haiku-4-5-20251001",
"messages": [{"role": "user", "content": "Hello"}]
}))
.send()
.await?
.json()
.await?;
println!("{resp:#}");
Ok(())
}import java.net.URI;
import java.net.http.*;
public class CountTokens {
public static void main(String[] args) throws Exception {
String body = """
{"model":"claude-haiku-4-5-20251001",
"messages":[{"role":"user","content":"Hello"}]}
""";
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.sakrylle.com/v1/messages/count_tokens"))
.header("Authorization", "Bearer sk-xxxxxxxxxxxxxxxx")
.header("Content-Type", "application/json")
.header("anthropic-version", "2023-06-01")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());
}
}using System.Net.Http.Headers;
using System.Text;
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "sk-xxxxxxxxxxxxxxxx");
http.DefaultRequestHeaders.Add("anthropic-version", "2023-06-01");
var payload = """
{"model":"claude-haiku-4-5-20251001",
"messages":[{"role":"user","content":"Hello"}]}
""";
var resp = await http.PostAsync(
"https://api.sakrylle.com/v1/messages/count_tokens",
new StringContent(payload, Encoding.UTF8, "application/json"));
Console.WriteLine(await resp.Content.ReadAsStringAsync());