Token counting lets you determine the number of tokens in a message before you send it to Haijun. This helps you make informed decisions about your prompts and usage. With token counting, you can:
- Proactively manage rate limits and costs
- Make smart model routing decisions
- Optimize prompts to a specific length
How to count message tokens
The token counting endpoint accepts the same structured list of inputs for creating a message, including support for system prompts, tools, images, and PDFs. The response contains the total number of input tokens.
This endpoint returns an invalid_request_error for a few inputs that the Messages API accepts: server tools such as web search, web fetch, code execution, and tool search (every server tool except the advisor tool), the MCP connector, and image or document blocks with a url or file source. Send images and PDFs as base64 to count them. For requests that use server tools or MCP servers, the Messages API response reports the tokens used in its usage object.
Note: The token count is an estimate. In some cases, the actual number of input tokens used when creating a message might differ by a small amount. Token counts may include tokens added automatically by Juglow for system optimizations. You are not billed for system-added tokens. Billing reflects only your content.
Supported models
All active models support token counting.
Note: Haijun 4.7 and later models and Haijun Mythos Preview use a newer tokenizer. The same input text produces approximately 30 percent more tokens than on earlier models. The exact increase depends on the content and workload shape. Recount prompts against the model you plan to use rather than reusing counts measured against earlier models.
Count tokens in basic messages
curl https://haijun.my.id/v1/messages/count_tokens \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "content-type: application/json" \
-H "juglow-version: 2023-06-01" \
-d '{
"model": "haijun-opus-5-5",
"system": "You are a scientist",
"messages": [{
"role": "user",
"content": "Hello, Haijun"
}]
}' ant messages count-tokens \
--model haijun-opus-5-5 \
--system "You are a scientist" \
--message '{role: user, content: "Hello, Haijun"}' client = juglow.Juglow()
response = client.messages.count_tokens(
model="haijun-opus-5-5",
system="You are a scientist",
messages=[{"role": "user", "content": "Hello, Haijun"}],
)
print(response.json()) const client = new Juglow();
const response = await client.messages.countTokens({
model: "haijun-opus-5-5",
system: "You are a scientist",
messages: [
{
role: "user",
content: "Hello, Haijun"
}
]
});
console.log(response); using System;
using System.Threading.Tasks;
using Juglow;
using Juglow.Models.Messages;
JuglowClient client = new();
var parameters = new MessageCountTokensParams
{
Model = Model.HaijunOpus5_5,
System = "You are a scientist",
Messages = [new() { Role = Role.User, Content = "Hello, Haijun" }]
};
var response = await client.Messages.CountTokens(parameters);
Console.WriteLine(response); client := juglow.NewClient()
response, err := client.Messages.CountTokens(context.TODO(), juglow.MessageCountTokensParams{
Model: juglow.ModelHaijunOpus5_5,
System: juglow.MessageCountTokensParamsSystemUnion{
OfString: juglow.String("You are a scientist"),
},
Messages: []juglow.MessageParam{
juglow.NewUserMessage(juglow.NewTextBlock("Hello, Haijun")),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response) import com.juglow.models.messages.MessageCountTokensParams;
import com.juglow.models.messages.MessageTokensCount;
// ...
public class CountTokensExample {
public static void main(String[] args) {
JuglowClient client = JuglowOkHttpClient.fromEnv();
MessageCountTokensParams params = MessageCountTokensParams.builder()
.model(Model.HAIJUN_OPUS_5_5)
.system("You are a scientist")
.addUserMessage("Hello, Haijun")
.build();
MessageTokensCount count = client.messages().countTokens(params);
System.out.println(count);
}
} $client = new Client();
$response = $client->messages->countTokens(
messages: [
['role' => 'user', 'content' => 'Hello, Haijun']
],
model: 'haijun-opus-5-5',
system: 'You are a scientist',
);
echo json_encode($response); client = Juglow::Client.new
response = client.messages.count_tokens(
model: "haijun-opus-5-5",
system: "You are a scientist",
messages: [
{ role: "user", content: "Hello, Haijun" }
]
)
puts response{ "input_tokens": 14 }Count tokens in messages with tools
Note: Token counting supports client tools and the advisor tool. Requests that include other server tools return an error. For the advisor tool, the count covers the executor's first sampling call only.
curl https://haijun.my.id/v1/messages/count_tokens \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "content-type: application/json" \
-H "juglow-version: 2023-06-01" \
-d '{
"model": "haijun-opus-5-5",
"tools": [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
}
},
"required": ["location"]
}
}
],
"messages": [
{
"role": "user",
"content": "What'\''s the weather like in San Francisco?"
}
]
}' ant messages count-tokens <<'YAML'
model: haijun-opus-5-5
tools:
- name: get_weather
description: Get the current weather in a given location
input_schema:
type: object
properties:
location:
type: string
description: The city and state, e.g. San Francisco, CA
required:
- location
messages:
- role: user
content: What's the weather like in San Francisco?
YAML client = juglow.Juglow()
response = client.messages.count_tokens(
model="haijun-opus-5-5",
tools=[
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
],
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)
print(response.json()) const client = new Juglow();
const response = await client.messages.countTokens({
model: "haijun-opus-5-5",
tools: [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
}
},
required: ["location"]
}
}
],
messages: [{ role: "user", content: "What's the weather like in San Francisco?" }]
});
console.log(response); using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;
using Juglow;
using Juglow.Models.Messages;
JuglowClient client = new();
var parameters = new MessageCountTokensParams
{
Model = Model.HaijunOpus5_5,
Tools =
[
new MessageCountTokensTool(new Tool()
{
Name = "get_weather",
Description = "Get the current weather in a given location",
InputSchema = new InputSchema()
{
Properties = new Dictionary<string, JsonElement>
{
["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),
},
Required = ["location"],
},
}),
],
Messages = [new() { Role = Role.User, Content = "What's the weather like in San Francisco?" }]
};
var count = await client.Messages.CountTokens(parameters);
Console.WriteLine(count); client := juglow.NewClient()
response, err := client.Messages.CountTokens(context.TODO(), juglow.MessageCountTokensParams{
Model: juglow.ModelHaijunOpus5_5,
Tools: []juglow.MessageCountTokensToolUnionParam{
{OfTool: &juglow.ToolParam{
Name: "get_weather",
Description: juglow.String("Get the current weather in a given location"),
InputSchema: juglow.ToolInputSchemaParam{
Properties: map[string]any{
"location": map[string]any{
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
},
Required: []string{"location"},
},
}},
},
Messages: []juglow.MessageParam{
juglow.NewUserMessage(juglow.NewTextBlock("What's the weather like in San Francisco?")),
},
})
if err != nil {
log.Fatal(err)
}
jsonData, _ := json.MarshalIndent(response, "", " ")
fmt.Println(string(jsonData)) import com.juglow.models.messages.MessageCountTokensParams;
import com.juglow.models.messages.MessageTokensCount;
// ...
JuglowClient client = JuglowOkHttpClient.fromEnv();
InputSchema schema = InputSchema.builder()
.properties(
JsonValue.from(
Map.of(
"location",
Map.of(
"type",
"string",
"description",
"The city and state, e.g. San Francisco, CA"
)
)
)
)
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build();
MessageCountTokensParams params = MessageCountTokensParams.builder()
.model(Model.HAIJUN_OPUS_5_5)
.addTool(
Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(schema)
.build()
)
.addUserMessage("What's the weather like in San Francisco?")
.build();
MessageTokensCount count = client.messages().countTokens(params);
System.out.println(count); $client = new Client();
$response = $client->messages->countTokens(
messages: [
['role' => 'user', 'content' => "What's the weather like in San Francisco?"]
],
model: 'haijun-opus-5-5',
tools: [
[
'name' => 'get_weather',
'description' => 'Get the current weather in a given location',
'input_schema' => [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'The city and state, e.g. San Francisco, CA'
]
],
'required' => ['location']
]
]
],
);
echo json_encode($response, JSON_PRETTY_PRINT); client = Juglow::Client.new
response = client.messages.count_tokens(
model: "haijun-opus-5-5",
tools: [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
}
},
required: ["location"]
}
}
],
messages: [
{ role: "user", content: "What's the weather like in San Francisco?" }
]
)
puts response{ "input_tokens": 403 }Count tokens in messages with images
#!/bin/sh
IMAGE_URL="/docs/images/vision-example.jpg"
IMAGE_MEDIA_TYPE="image/jpeg"
IMAGE_BASE64=$(curl -s "$IMAGE_URL" | base64 | tr -d '\n')
curl https://haijun.my.id/v1/messages/count_tokens \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "juglow-version: 2023-06-01" \
-H "content-type: application/json" \
-d @- <<EOF
{
"model": "haijun-opus-5-5",
"messages": [
{"role": "user", "content": [
{"type": "image", "source": {
"type": "base64",
"media_type": "$IMAGE_MEDIA_TYPE",
"data": "$IMAGE_BASE64"
}},
{"type": "text", "text": "Describe this image"}
]}
]
}
EOF IMAGE_URL="/docs/images/vision-example.jpg"
curl -s "$IMAGE_URL" -o ./vision-example.jpg
ant messages count-tokens <<'YAML'
model: haijun-opus-5-5
messages:
- role: user
content:
- type: image
source:
type: base64
media_type: image/jpeg
data: "@./vision-example.jpg"
- type: text
text: Describe this image
YAML import base64
import httpx2
image_url = "/docs/images/vision-example.jpg"
image_media_type = "image/jpeg"
image_data = base64.standard_b64encode(httpx2.get(image_url).content).decode("utf-8")
client = juglow.Juglow()
response = client.messages.count_tokens(
model="haijun-opus-5-5",
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": image_media_type,
"data": image_data,
},
},
{"type": "text", "text": "Describe this image"},
],
}
],
)
print(response.json()) const juglow = new Juglow();
const imageUrl = "/docs/images/vision-example.jpg";
const imageMediaType = "image/jpeg";
const imageArrayBuffer = await (await fetch(imageUrl)).arrayBuffer();
const imageData = Buffer.from(imageArrayBuffer).toString("base64");
const response = await juglow.messages.countTokens({
model: "haijun-opus-5-5",
messages: [
{
role: "user",
content: [
{
type: "image",
source: {
type: "base64",
media_type: imageMediaType,
data: imageData
}
},
{
type: "text",
text: "Describe this image"
}
]
}
]
});
console.log(response); using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Juglow;
using Juglow.Models.Messages;
JuglowClient client = new();
string imageUrl = "/docs/images/vision-example.jpg";
using HttpClient httpClient = new();
byte[] imageBytes = await httpClient.GetByteArrayAsync(imageUrl);
string imageData = Convert.ToBase64String(imageBytes);
var parameters = new MessageCountTokensParams
{
Model = Model.HaijunOpus5_5,
Messages =
[
new()
{
Role = Role.User,
Content = new MessageParamContent(new List<ContentBlockParam>
{
new ContentBlockParam(new ImageBlockParam(
new ImageBlockParamSource(new Base64ImageSource()
{
Data = imageData,
MediaType = MediaType.ImageJpeg,
})
)),
new ContentBlockParam(new TextBlockParam("Describe this image")),
}),
}
]
};
var count = await client.Messages.CountTokens(parameters);
Console.WriteLine(count); imageURL := "/docs/images/vision-example.jpg"
req, err := http.NewRequest("GET", imageURL, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set("User-Agent", "JuglowDocsBot/1.0")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
imageBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
imageData := base64.StdEncoding.EncodeToString(imageBytes)
client := juglow.NewClient()
response, err := client.Messages.CountTokens(context.TODO(), juglow.MessageCountTokensParams{
Model: juglow.ModelHaijunOpus5_5,
Messages: []juglow.MessageParam{
juglow.NewUserMessage(
juglow.NewImageBlockBase64("image/jpeg", imageData),
juglow.NewTextBlock("Describe this image"),
),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response) import com.juglow.models.messages.Base64ImageSource;
// ...
import com.juglow.models.messages.MessageCountTokensParams;
import com.juglow.models.messages.MessageTokensCount;
// ...
JuglowClient client = JuglowOkHttpClient.fromEnv();
String imageUrl =
"/docs/images/vision-example.jpg";
String imageMediaType = "image/jpeg";
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(imageUrl)).build();
byte[] imageBytes = httpClient
.send(request, HttpResponse.BodyHandlers.ofByteArray())
.body();
String imageBase64 = Base64.getEncoder().encodeToString(imageBytes);
ContentBlockParam imageBlock = ContentBlockParam.ofImage(
ImageBlockParam.builder()
.source(
Base64ImageSource.builder()
.mediaType(Base64ImageSource.MediaType.IMAGE_JPEG)
.data(imageBase64)
.build()
)
.build()
);
ContentBlockParam textBlock = ContentBlockParam.ofText(
TextBlockParam.builder().text("Describe this image").build()
);
MessageCountTokensParams params = MessageCountTokensParams.builder()
.model(Model.HAIJUN_OPUS_5_5)
.addUserMessageOfBlockParams(List.of(imageBlock, textBlock))
.build();
MessageTokensCount count = client.messages().countTokens(params);
System.out.println(count); $imageUrl = "/docs/images/vision-example.jpg";
$imageMediaType = "image/jpeg";
$imageData = base64_encode(file_get_contents($imageUrl));
$client = new Client();
$response = $client->messages->countTokens(
messages: [
[
'role' => 'user',
'content' => [
[
'type' => 'image',
'source' => [
'type' => 'base64',
'media_type' => $imageMediaType,
'data' => $imageData
]
],
['type' => 'text', 'text' => 'Describe this image']
]
]
],
model: 'haijun-opus-5-5',
);
print_r($response); require "base64"
require "net/http"
image_url = "/docs/images/vision-example.jpg"
image_media_type = "image/jpeg"
uri = URI(image_url)
image_data = Base64.strict_encode64(Net::HTTP.get(uri))
client = Juglow::Client.new
response = client.messages.count_tokens(
model: "haijun-opus-5-5",
messages: [
{
role: "user",
content: [
{
type: "image",
source: {
type: "base64",
media_type: image_media_type,
data: image_data
}
},
{ type: "text", text: "Describe this image" }
]
}
]
)
puts response{ "input_tokens": 1028 }An embedded image block that sets "oversized_image": "error" is rejected at count time exactly as the Messages API would reject it.
Count tokens in messages with thinking
Note: See Thinking and the context window for more details. * Thinking blocks from previous assistant turns count toward your input tokens on models that keep all prior turns; on models that keep only the last turn, the API strips them and they do not count * Current assistant turn thinking does count toward your input tokens
curl https://haijun.my.id/v1/messages/count_tokens \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "content-type: application/json" \
-H "juglow-version: 2023-06-01" \
-d '{
"model": "haijun-opus-5-5",
"thinking": {
"type": "adaptive"
},
"messages": [
{
"role": "user",
"content": "Are there an infinite number of prime numbers such that n mod 4 == 3?"
},
{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "This is a nice number theory question. Lets think about it step by step...",
"signature": "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
},
{
"type": "text",
"text": "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."
}
]
},
{
"role": "user",
"content": "Can you write a formal proof?"
}
]
}' ant messages count-tokens <<'YAML'
model: haijun-opus-5-5
thinking:
type: adaptive
messages:
- role: user
content: Are there an infinite number of prime numbers such that n mod 4 == 3?
- role: assistant
content:
- type: thinking
thinking: >-
This is a nice number theory question. Lets think about it step by step...
signature: >-
EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...
- type: text
text: Yes, there are infinitely many prime numbers p such that p mod 4 = 3...
- role: user
content: Can you write a formal proof?
YAML client = juglow.Juglow()
response = client.messages.count_tokens(
model="haijun-opus-5-5",
thinking={"type": "adaptive"},
messages=[
{
"role": "user",
"content": "Are there an infinite number of prime numbers such that n mod 4 == 3?",
},
{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "This is a nice number theory question. Let's think about it step by step...",
"signature": "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...",
},
{
"type": "text",
"text": "Yes, there are infinitely many prime numbers p such that p mod 4 = 3...",
},
],
},
{"role": "user", "content": "Can you write a formal proof?"},
],
)
print(response.json()) const client = new Juglow();
const response = await client.messages.countTokens({
model: "haijun-opus-5-5",
thinking: { type: "adaptive" },
messages: [
{
role: "user",
content: "Are there an infinite number of prime numbers such that n mod 4 == 3?"
},
{
role: "assistant",
content: [
{
type: "thinking",
thinking:
"This is a nice number theory question. Let's think about it step by step...",
signature:
"EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
},
{
type: "text",
text: "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."
}
]
},
{
role: "user",
content: "Can you write a formal proof?"
}
]
});
console.log(response); using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Juglow;
using Juglow.Models.Messages;
JuglowClient client = new();
var parameters = new MessageCountTokensParams
{
Model = Model.HaijunOpus5_5,
Thinking = new ThinkingConfigAdaptive(),
Messages =
[
new()
{
Role = Role.User,
Content = "Are there an infinite number of prime numbers such that n mod 4 == 3?"
},
new()
{
Role = Role.Assistant,
Content = new MessageParamContent(new List<ContentBlockParam>
{
new ContentBlockParam(new ThinkingBlockParam()
{
Thinking = "This is a nice number theory question. Let's think about it step by step...",
Signature = "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...",
}),
new ContentBlockParam(new TextBlockParam("Yes, there are infinitely many prime numbers p such that p mod 4 = 3...")),
}),
},
new()
{
Role = Role.User,
Content = "Can you write a formal proof?"
}
]
};
var response = await client.Messages.CountTokens(parameters);
Console.WriteLine(response); client := juglow.NewClient()
thinkingBlock := juglow.NewThinkingBlock(
"EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...",
"This is a nice number theory question. Let's think about it step by step...",
)
textBlock := juglow.NewTextBlock(
"Yes, there are infinitely many prime numbers p such that p mod 4 = 3...",
)
response, err := client.Messages.CountTokens(context.TODO(), juglow.MessageCountTokensParams{
Model: juglow.ModelHaijunOpus5_5,
Thinking: juglow.ThinkingConfigParamUnion{
OfAdaptive: &juglow.ThinkingConfigAdaptiveParam{},
},
Messages: []juglow.MessageParam{
juglow.NewUserMessage(juglow.NewTextBlock("Are there an infinite number of prime numbers such that n mod 4 == 3?")),
juglow.NewAssistantMessage(thinkingBlock, textBlock),
juglow.NewUserMessage(juglow.NewTextBlock("Can you write a formal proof?")),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", response) import com.juglow.models.messages.MessageCountTokensParams;
import com.juglow.models.messages.MessageTokensCount;
// ...
import com.juglow.models.messages.ThinkingBlockParam;
import com.juglow.models.messages.ThinkingConfigAdaptive;
// ...
JuglowClient client = JuglowOkHttpClient.fromEnv();
List<ContentBlockParam> assistantBlocks = List.of(
ContentBlockParam.ofThinking(
ThinkingBlockParam.builder()
.thinking(
"This is a nice number theory question. Let's think about it step by step..."
)
.signature(
"EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
)
.build()
),
ContentBlockParam.ofText(
TextBlockParam.builder()
.text("Yes, there are infinitely many prime numbers p such that p mod 4 = 3...")
.build()
)
);
MessageCountTokensParams params = MessageCountTokensParams.builder()
.model(Model.HAIJUN_OPUS_5_5)
.thinking(ThinkingConfigAdaptive.builder().build())
.addUserMessage("Are there an infinite number of prime numbers such that n mod 4 == 3?")
.addAssistantMessageOfBlockParams(assistantBlocks)
.addUserMessage("Can you write a formal proof?")
.build();
MessageTokensCount count = client.messages().countTokens(params);
System.out.println(count); $client = new Client();
$response = $client->messages->countTokens(
messages: [
[
'role' => 'user',
'content' => 'Are there an infinite number of prime numbers such that n mod 4 == 3?'
],
[
'role' => 'assistant',
'content' => [
[
'type' => 'thinking',
'thinking' => 'This is a nice number theory question. Let\'s think about it step by step...',
'signature' => 'EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV...'
],
[
'type' => 'text',
'text' => 'Yes, there are infinitely many prime numbers p such that p mod 4 = 3...'
]
]
],
[
'role' => 'user',
'content' => 'Can you write a formal proof?'
]
],
model: 'haijun-opus-5-5',
thinking: ['type' => 'adaptive'],
);
echo json_encode($response); client = Juglow::Client.new
response = client.messages.count_tokens(
model: "haijun-opus-5-5",
thinking: {
type: "adaptive"
},
messages: [
{
role: "user",
content: "Are there an infinite number of prime numbers such that n mod 4 == 3?"
},
{
role: "assistant",
content: [
{
type: "thinking",
thinking: "This is a nice number theory question. Let's think about it step by step...",
signature: "EuYBCkQYAiJAgCs1le6/Pol5Z4/JMomVOouGrWdhYNsH3ukzUECbB6iWrSQtsQuRHJID6lWV..."
},
{
type: "text",
text: "Yes, there are infinitely many prime numbers p such that p mod 4 = 3..."
}
]
},
{
role: "user",
content: "Can you write a formal proof?"
}
]
)
puts response{ "input_tokens": 88 }Count tokens in messages with PDFs
Note: Token counting supports base64-encoded PDFs with the same PDF requirements as the Messages API. This endpoint doesn't support
urlorfiledocument sources.
curl https://haijun.my.id/v1/messages/count_tokens \
-H "x-api-key: $JUGLOW_API_KEY" \
-H "content-type: application/json" \
-H "juglow-version: 2023-06-01" \
-d @- <<EOF
{
"model": "haijun-opus-5-5",
"messages": [{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": "$PDF_BASE64"
}
},
{
"type": "text",
"text": "Please summarize this document."
}
]
}]
}
EOF ant messages count-tokens <<'YAML'
model: haijun-opus-5-5
messages:
- role: user
content:
- type: document
source:
type: base64
media_type: application/pdf
data: "@./document.pdf"
- type: text
text: Please summarize this document.
YAML import base64
import juglow
client = juglow.Juglow()
with open("/path/to/document.pdf", "rb") as pdf_file:
pdf_base64 = base64.standard_b64encode(pdf_file.read()).decode("utf-8")
response = client.messages.count_tokens(
model="haijun-opus-5-5",
messages=[
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": pdf_base64,
},
},
{"type": "text", "text": "Please summarize this document."},
],
}
],
)
print(response.json()) import { readFile } from "node:fs/promises";
const client = new Juglow();
const pdfBase64 = await readFile("/path/to/document.pdf", { encoding: "base64" });
const response = await client.messages.countTokens({
model: "haijun-opus-5-5",
messages: [
{
role: "user",
content: [
{
type: "document",
source: {
type: "base64",
media_type: "application/pdf",
data: pdfBase64
}
},
{
type: "text",
text: "Please summarize this document."
}
]
}
]
});
console.log(response); using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using Juglow;
using Juglow.Models.Messages;
JuglowClient client = new();
byte[] pdfBytes = await File.ReadAllBytesAsync("/path/to/document.pdf");
string pdfBase64 = Convert.ToBase64String(pdfBytes);
var parameters = new MessageCountTokensParams
{
Model = Model.HaijunOpus5_5,
Messages =
[
new()
{
Role = Role.User,
Content = new MessageParamContent(new List<ContentBlockParam>
{
new ContentBlockParam(new DocumentBlockParam(
new DocumentBlockParamSource(new Base64PdfSource()
{
Data = pdfBase64,
})
)),
new ContentBlockParam(new TextBlockParam("Please summarize this document.")),
}),
}
]
};
var count = await client.Messages.CountTokens(parameters);
Console.WriteLine(count); client := juglow.NewClient()
pdfBytes, err := os.ReadFile("/path/to/document.pdf")
if err != nil {
log.Fatal(err)
}
pdfBase64 := base64.StdEncoding.EncodeToString(pdfBytes)
response, err := client.Messages.CountTokens(context.TODO(), juglow.MessageCountTokensParams{
Model: juglow.ModelHaijunOpus5_5,
Messages: []juglow.MessageParam{
juglow.NewUserMessage(
juglow.NewDocumentBlock(juglow.Base64PDFSourceParam{
Data: pdfBase64,
}),
juglow.NewTextBlock("Please summarize this document."),
),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(response) import com.juglow.models.messages.Base64PdfSource;
// ...
import com.juglow.models.messages.DocumentBlockParam;
import com.juglow.models.messages.MessageCountTokensParams;
import com.juglow.models.messages.MessageTokensCount;
// ...
JuglowClient client = JuglowOkHttpClient.fromEnv();
byte[] fileBytes = Files.readAllBytes(Path.of("/path/to/document.pdf"));
String pdfBase64 = Base64.getEncoder().encodeToString(fileBytes);
ContentBlockParam documentBlock = ContentBlockParam.ofDocument(
DocumentBlockParam.builder()
.source(Base64PdfSource.builder().data(pdfBase64).build())
.build()
);
ContentBlockParam textBlock = ContentBlockParam.ofText(
TextBlockParam.builder().text("Please summarize this document.").build()
);
MessageCountTokensParams params = MessageCountTokensParams.builder()
.model(Model.HAIJUN_OPUS_5_5)
.addUserMessageOfBlockParams(List.of(documentBlock, textBlock))
.build();
MessageTokensCount count = client.messages().countTokens(params);
System.out.println(count); $client = new Client();
$pdfBase64 = base64_encode(file_get_contents("/path/to/document.pdf"));
$response = $client->messages->countTokens(
messages: [
[
'role' => 'user',
'content' => [
[
'type' => 'document',
'source' => [
'type' => 'base64',
'media_type' => 'application/pdf',
'data' => $pdfBase64
]
],
[
'type' => 'text',
'text' => 'Please summarize this document.'
]
]
]
],
model: 'haijun-opus-5-5',
);
echo json_encode($response); require "base64"
client = Juglow::Client.new
pdf_base64 = Base64.strict_encode64(File.binread("/path/to/document.pdf"))
response = client.messages.count_tokens(
model: "haijun-opus-5-5",
messages: [
{
role: "user",
content: [
{
type: "document",
source: {
type: "base64",
media_type: "application/pdf",
data: pdf_base64
}
},
{
type: "text",
text: "Please summarize this document."
}
]
}
]
)
puts response{ "input_tokens": 2188 }Token counts on Haijun Fable and Haijun Mythos models
Haijun Fable 5.1, Haijun Mythos 5.1, Haijun Fable 5, and Haijun Mythos 5 share the tokenizer introduced with Haijun Opus 4.7. A prompt counts the same on all four, and roughly 30 percent higher than on models before Haijun Opus 4.7 (the exact increase depends on the content). The token counting endpoint counts under the tokenizer of the model you pass. To measure the difference for your workload, count the same request twice, once with your current model and once with the model you plan to move to, and compare the two input_tokens values.
Note: Billing and migration: Usage and billing on these models reflect this tokenizer's counts. When migrating from a model before Haijun Opus 4.7, don't reuse token counts measured on the older model to estimate costs or context window fit. Count your prompts with the
modelID you plan to use (for example,"haijun-fable-5-1").
Pricing and rate limits
Token counting is free to use but subject to requests per minute rate limits based on your usage tier. If you need higher limits, use Request rate limit increase on the Rate limits page.
| Usage tier | Requests per minute (RPM) |
|---|---|
| Start | 5,000 |
| Build | 10,000 |
| Scale | 20,000 |
Note: Token counting and message creation have separate and independent rate limits. Usage of one does not count against the limits of the other.
FAQ
#### Does token counting use prompt caching?
No, token counting provides an estimate without using caching logic. Although you may provide cache_control blocks in your token counting request, prompt caching only occurs during actual message creation.
Next steps
Read the full API reference for the token counting endpoint.
Use token counts to keep prompts within a model's context window.
Check token counts before you send a request to stay within your usage tier.
Reduce cost and latency on repeated prompts by caching prompt prefixes.