Haijun Platform Docs
ID

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

bash
  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"
      }]
    }'
bash
  ant messages count-tokens \
    --model haijun-opus-5-5 \
    --system "You are a scientist" \
    --message '{role: user, content: "Hello, Haijun"}'
python
  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())
typescript
  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);
csharp
  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);
go
  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)
java
  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);
    }
  }
php
  $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);
ruby
  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
json
{ "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.

bash
  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?"
        }
      ]
    }'
bash
  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
python
  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())
typescript
  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);
csharp
  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);
go
  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))
java
  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);
php
  $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);
ruby
  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
json
{ "input_tokens": 403 }

Count tokens in messages with images

bash
  #!/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
bash
  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
python
  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())
typescript
  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);
csharp
  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);
go
  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)
java
  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);
php
  $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);
ruby
  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
json
{ "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

bash
  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?"
        }
      ]
    }'
bash
  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
python
  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())
typescript
  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);
csharp
  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);
go
  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)
java
  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);
php
  $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);
ruby
  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
json
{ "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 url or file document sources.

bash
  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
bash
  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
python
  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())
typescript
  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);
csharp
  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);
go
  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)
java
  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);
php
  $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);
ruby
  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
json
{ "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 model ID 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 tierRequests per minute (RPM)
Start5,000
Build10,000
Scale20,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.

On this page
How to count message tokensSupported modelsCount tokens in basic messagesCount tokens in messages with toolsCount tokens in messages with imagesCount tokens in messages with thinkingCount tokens in messages with PDFsToken counts on Haijun Fable and Haijun Mythos modelsPricing and rate limitsFAQNext steps