Anthropic Messages API

The /v1/messages endpoint, compatible with the Anthropic SDK and Claude Code

Onysoft also serves the Anthropic Messages API format. Code written with the Anthropic SDK and Claude Code work by changing only the base address and the key; the same sk-ony- key, balance and model catalog are used. Non-Claude models can be called through this endpoint too. For Claude Code setup see the Claude Code section.

POST /v1/messages

Creates a message (streaming or non-streaming). The response is an Anthropic Message object or Anthropic SSE events.

POST /v1/messages/count_tokens

Returns the input token count of a request. Free of charge; nothing is deducted from your balance.

GET /v1/models

Called with the anthropic-version header, returns the model list in the Anthropic format (see Models API).

Base Address and Authentication

In the Anthropic SDK and in Claude Code the base address must be https://api.onysoft.com; the client adds the /v1/messages path itself. The key can be sent two ways: Authorization: Bearer sk-ony-... or x-api-key: sk-ony-.... If both are present, Authorization is used. The SDKs send the anthropic-version header themselves (e.g. 2023-06-01). x-api-key is accepted only on these endpoints; other endpoints such as /v1/chat/completions require Authorization: Bearer.

warning

Do not append /v1. If the base address is set to https://api.onysoft.com/v1, the request goes to /v1/v1/messages and returns 404; Claude Code shows this as "There's an issue with the selected model". The OpenAI SDK, on the other hand, expects https://api.onysoft.com/v1.

Example Request

cURL
curl https://api.onysoft.com/v1/messages \
  -H "x-api-key: $ONYSOFT_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-5.5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Merhaba!"}]
  }'
Python
import os
from anthropic import Anthropic

client = Anthropic(
    base_url="https://api.onysoft.com",  # do not append /v1
    api_key=os.environ["ONYSOFT_API_KEY"],
)

message = client.messages.create(
    model="anthropic/claude-sonnet-5.5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Merhaba!"}],
)
print(message.content[0].text)
Node.js
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
    baseURL: 'https://api.onysoft.com',  // do not append /v1
    apiKey: process.env.ONYSOFT_API_KEY,
});

const message = await client.messages.create({
    model: 'anthropic/claude-sonnet-5.5',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Merhaba!' }],
});
console.log(message.content[0].text);

Model Names

In the model field you can use the catalog id (anthropic/claude-sonnet-5.5) or the Anthropic id (claude-sonnet-5-5, claude-haiku-4-5-20251001); Anthropic ids are mapped to their catalog counterpart. Names such as claude-sonnet-latest go to the ~anthropic/claude-sonnet-latest alias. Unprefixed names that match exactly one model in the catalog are resolved too. A model that is not in the catalog, or that your key is not allowed to use, returns 404 not_found_error. Non-Claude models (e.g. openai/gpt-5.5, z-ai/glm-5.3:tr) can be called through this endpoint as well: the request is translated to the chat format and the response still comes back in the Anthropic format.

Supported and Unsupported Fields

Token Counting

POST /v1/messages/count_tokens returns the input token count as {"input_tokens": N}; it is free. On Claude models the count is done by Anthropic. On other models (or if counting is not possible) an approximate estimate is returned and the response carries the X-Onysoft-Token-Count: estimate header. Your key's model permissions apply here too, and the request counts toward the per-minute request limit.

JSON
// POST /v1/messages/count_tokens
{ "model": "anthropic/claude-sonnet-5.5", "messages": [{ "role": "user", "content": "Merhaba!" }] }

// 200
{ "input_tokens": 10 }

Response and Streaming

A non-streaming request returns an Anthropic Message object (id, type: "message", content, stop_reason, usage). With stream: true you receive Anthropic SSE events: message_start, content_block_start, content_block_delta, content_block_stop, message_delta and message_stop. An error that occurs after the stream has started is reported with an event: error event; for transient conditions the error type is overloaded_error and Claude Code retries the request itself.

Error Format

JSON
{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "model: claude-example not found"
  }
}

Errors on these endpoints use the Anthropic format; there are no success, code or param fields. Types: 400 invalid_request_error, 401 authentication_error, 402 billing_error, 403 permission_error, 404 not_found_error, 413 request_too_large, 429 rate_limit_error, 503 overloaded_error, 504 timeout_error, other 5xx api_error. A model that is not allowed or not in the catalog returns 404 not_found_error. The 402 message states the required and the available amount.

Billing

Charges are taken from actual usage with the same rule and the same model price as Chat Completions. Before the request a balance pre-check is made based on max_tokens (see Balance pre-check). count_tokens is free.

Want help finding the right model?