HelipodDocs

Anthropic compatible

Messages with the Anthropic SDKs, curl and Claude Code, streaming, thinking, token counting and format conversion.

Point any Anthropic client at https://ai.helipod.io and use a Helipod AI key. The request and response follow the Anthropic Messages API, for every model in the catalog.

POST/v1/messages
Create a message. Charged to your AI balance by the tokens used.
POST/v1/messages/count_tokens
Estimate the input tokens of a messages request. Free.

Request

The body is an Anthropic messages request: model, max_tokens, messages, and optionally system, stream, temperature, top_p, stop_sequences, tools, tool_choice, thinking and metadata.

  • model is a Helipod model id from GET /v1/models, for example glm-5.3.
  • max_tokens above the model's output limit is lowered to that limit instead of failing.
  • anthropic-version and anthropic-beta headers are passed on when you send them. Without anthropic-version, 2023-06-01 is used.

Examples

curl https://ai.helipod.io/v1/messages \
  -H "x-api-key: hel_ai_your_key" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3",
    "max_tokens": 2000,
    "system": "You are a concise assistant.",
    "messages": [
      { "role": "user", "content": "Explain what a VPS is in two sentences." }
    ]
  }'

The base URL for the Anthropic SDKs is https://ai.helipod.io, without /v1: the SDK adds /v1/messages itself. The OpenAI SDKs are the other way round.

Response

A standard Anthropic message:

{
  "id": "msg_0b7e4c1f9a2d4e8b8c6f1a3d",
  "type": "message",
  "role": "assistant",
  "model": "glm-5.3",
  "content": [
    { "type": "thinking", "thinking": "The user wants a short definition...", "signature": "" },
    { "type": "text", "text": "A VPS is a virtual server with its own operating system and root access..." }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 226,
    "output_tokens": 310,
    "cache_read_input_tokens": 1024,
    "cache_creation_input_tokens": 0
  }
}

The response headers are the same as on the OpenAI route (x-request-id, x-helipod-model and the retirement headers). See Response headers.

Token usage

Anthropic counts the prompt differently from OpenAI: input_tokens excludes the cached part.

FieldMeaningBilled as
usage.input_tokensPrompt tokens that were not read from or written to the cache.Input
usage.cache_read_input_tokensPrompt tokens read from the model's prompt cache.Cached input (cheaper)
usage.cache_creation_input_tokensPrompt tokens written to the cache, on models that report them.The model's cache-write price (input price when it has none)
usage.output_tokensEverything the model wrote, including thinking.Output

The whole prompt is input_tokens + cache_read_input_tokens + cache_creation_input_tokens. That total decides the price tier on models priced by prompt length.

Streaming

Set "stream": true to receive the standard event sequence: message_start, content_block_start, content_block_delta (text_delta, thinking_delta, input_json_delta), content_block_stop, message_delta, message_stop.

const stream = client.messages.stream({
  model: "deepseek-v4.1-flash",
  max_tokens: 2000,
  messages: [{ role: "user", content: "Write a haiku about Jakarta rain." }],
});

stream.on("text", (text) => process.stdout.write(text));
const final = await stream.finalMessage();
console.log("\n", final.usage);

Good to know:

  • Final usage is in message_delta. message_start may report zeros; the counts in message_delta are the ones that are billed.
  • Keep-alive while the model starts. If the model has not started after about 10 seconds, the gateway answers 200 and sends SSE comment lines (: waiting for the model, then : keep-alive every 15 seconds). SSE clients ignore them.
  • Errors after the 200 (while the gateway was waiting for a slow model) arrive as an event: error with an Anthropic error body. A stream that ends without message_stop did not finish. See Limits and errors.
  • Stopping early. If you close the connection mid-stream, the request is charged for what was generated up to then.

Thinking

Send thinking: { "type": "enabled", "budget_tokens": 4096 } to let a reasoning model think first. Thinking tokens are part of output_tokens, are billed as output, and count against max_tokens, so keep budget_tokens below max_tokens. If the budget is not below the model's output cap, the gateway lowers it to just under the cap.

Tools

tools (with input_schema), tool_choice (auto, any, tool, none) and tool_result blocks work as in the Anthropic API. Server-side tools (for example web search) are not available.

Counting tokens

POST/v1/messages/count_tokens
Free, never charged.

Send the same body you would send to /v1/messages:

curl https://ai.helipod.io/v1/messages/count_tokens \
  -H "x-api-key: hel_ai_your_key" \
  -H "Content-Type: application/json" \
  -d '{"model": "glm-5.3", "messages": [{"role": "user", "content": "Hello!"}]}'
{ "input_tokens": 18 }

The count is the gateway's own estimate, deliberately on the high side, and the response carries x-helipod-estimate: true. It is the same estimate used for holds. The real count is in usage after the request.

Claude Code

Claude Code speaks the Anthropic format, so it works with the gateway:

export ANTHROPIC_BASE_URL=https://ai.helipod.io
export ANTHROPIC_AUTH_TOKEN=hel_ai_your_key
export ANTHROPIC_MODEL=glm-5.3
export ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4.1-flash   # background tasks
claude

Set ANTHROPIC_MODEL (and the background model) to Helipod model ids. Claude Code's calls to /v1/messages/count_tokens are answered with the free estimate. A claude-* model id that is not in your model list may be answered by a default model chosen by Helipod; the x-helipod-model header shows which model served and billed the request.

OpenAI and Anthropic conversion

Every model accepts both formats. When you call a model in the format it does not speak natively, the gateway converts your request, calls the model, and converts the answer (plain or streamed) back to your format. Token counts are always read from the model's own answer, so billing is the same either way.

What carries over in both directions:

  • text, images (base64 and URL), system prompts;
  • tools, tool calls and tool results, and tool_choice;
  • stop sequences, temperature, top_p, the output cap;
  • thinking and reasoning, and stop/finish reasons;
  • token usage.

What changes or is dropped:

FromBehaviour
Anthropic thinking.budget_tokensBecomes reasoning_effort: up to 2,048 is low, up to 8,192 medium, more is high.
OpenAI reasoning_effortBecomes a thinking budget: minimal 1,024, low 2,048, medium 8,192, high 16,384 tokens (always below the output cap). temperature and top_p are dropped while thinking is on.
OpenAI temperatureCapped at 1.
OpenAI response_formatBecomes an instruction in the system prompt to answer with JSON (matching the schema, for json_schema).
Anthropic stop_sequencesOnly the first 4 are kept.
Anthropic cache_control, server toolsDropped. The model still caches automatically where it can.
OpenAI n above 1, logprobs, logit_bias, seedDropped.
Response idsNew ids are generated (msg_... or chatcmpl-...). Thinking blocks have an empty signature.

These rules apply only when a conversion happens. If an option you rely on seems to be ignored by a model, try the same request in the other format.

On this page