Count message tokens
POST/messages/count_tokens
Estimates how many input tokens a Messages request would use, without running it: free, even at zero credit, and no operator is called. It is an estimate — one token for every 4 characters of the system prompt, the messages and the tool schemas — because each model has its own tokenizer; what a real call costs is the usage its operator reports.
SoonOpening soon: what follows describes the service as it will work.
https://evanesca.app/api/v1/messages/count_tokensOpens at launchBearer $EVANESCA_API_KEYx-api-keystringrequiredYour key, which starts with sk-eva-. Authorization: Bearer followed by the key works too: that is where Claude Code sends it when ANTHROPIC_AUTH_TOKEN is set.
anthropic-versionstringSent by Anthropic's SDKs; accepted, and has no effect here.
Content-Typestringrequiredapplication/json: the body is JSON.
Request body
application/jsonmodelstringrequiredRequired by the format; the estimate does not depend on it.
messagesarrayrequiredThe turns, as for POST /messages.
system, toolsstring | array · arrayCounted as well when you send them.
Where it runs, what it costs
Evanesca · on the record
- Answered by
- Evanesca itself: no model runs, no operator is called.
- Costs
- Nothing: a valid key is enough, even with no credit left.
- Precision
- An estimate at 4 characters per token, never a billed amount. Long inline data, such as a base64 image, is left out of the count.
Errors
| Status | type | Meaning |
|---|---|---|
| 400 | invalid_ | The body is not valid JSON, or model or messages is missing. |
| 401 | invalid_ | No key, a malformed key, or a revoked one. |
Other operator errors reach you with its status and body, and Retry-After when it sends one (errors).
curl https://evanesca.app/api/v1/messages/count_tokens \
-H "x-api-key: $EVANESCA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "gemma-4-26b",
"messages": [{"role": "user", "content": "Hello"}]
}'import os
import anthropic
client = anthropic.Anthropic(
base_url="https://evanesca.app/api",
api_key=os.environ["EVANESCA_API_KEY"],
)
count = client.messages.count_tokens(
model="gemma-4-26b",
messages=[{"role": "user", "content": "Hello"}],
)
print(count.input_tokens)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://evanesca.app/api",
apiKey: process.env.EVANESCA_API_KEY,
});
const count = await client.messages.countTokens({
model: "gemma-4-26b",
messages: [{ role: "user", content: "Hello" }],
});
console.log(count.input_tokens);package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
body := strings.NewReader(`{"model":"gemma-4-26b","messages":[{"role":"user","content":"Hello"}]}`)
req, err := http.NewRequest("POST", "https://evanesca.app/api/v1/messages/count_tokens", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("EVANESCA_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}{
"input_tokens": 10
}{
"type": "error",
"error": {
"type": "invalid_api_key",
"message": "Invalid or missing API key."
}
}