Use Anthropic Messages

Send a Messages-shaped request with the Anthropic headers and base URL.

Set BASE_URL to your HTTPS API origin without a trailing slash or /v1, and pass API_KEY from your credential store. OpenAI-compatible SDKs use ${BASE_URL}/v1; Anthropic-compatible SDKs use BASE_URL.

Choose Messages for an Anthropic-compatible client. Its base URL is BASE_URL, without /v1. You need an organization key, an available model and credits.

Send one message

bash
printf 'x-api-key: %s\n' "$API_KEY" \
  | curl -q -H @- -i "$BASE_URL/v1/messages" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    -d '{
  "model": "gpt-5.6-sol",
  "max_tokens": 64,
  "messages": [
    {
      "role": "user",
      "content": "Say hello in one sentence."
    }
  ],
  "stream": false
}'

HTTP 200 returns a message object with content blocks and usage. Text lives in text blocks; the generated words vary. To estimate input tokens without generation, call POST /v1/messages/count_tokens with the same model and messages; it still counts toward the organization's request rate. For streaming event shapes, see streaming.

Read the response and usage

This shows a completed response shape; your ID, text, and token counts will differ:

json
{
  "id": "msg_018f3f407b447cc4b8ba3f62656c299c",
  "type": "message",
  "role": "assistant",
  "model": "gpt-5.6-sol",
  "content": [{ "type": "text", "text": "Done." }],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 12,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0,
    "output_tokens": 5
  }
}

Display text blocks in content; execute tool_use in a separate cycle only after validating the input arguments. stop_reason: max_tokens means a partial answer; tool_use means the turn awaits a tool result. In Messages, input_tokens is the uncached input portion: account for cache reads and writes when evaluating context use. The finalized credit debit is on API Activity.

Stream content blocks

Use -N to see native Messages events as they arrive. Generate one idempotency key so you can retry the same logical request after a disconnect:

bash
export UNLIMGPT_REQUEST_KEY="$(openssl rand -hex 16)"

Send the request from the same shell:

bash
test -n "${UNLIMGPT_REQUEST_KEY:-}" \
  && printf 'x-api-key: %s\n' "$API_KEY" \
  | curl -q -H @- -i -N "$BASE_URL/v1/messages" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $UNLIMGPT_REQUEST_KEY" \
    -d '{
  "model": "gpt-5.6-sol",
  "max_tokens": 64,
  "messages": [
    {
      "role": "user",
      "content": "Count to three."
    }
  ],
  "stream": true
}'

HTTP 200 starts the stream. message_start provides the message ID; content_block_start, content_block_delta, and content_block_stop delimit each text or tool block. Read the final stop_reason and usage from message_delta, then require message_stop before marking the call complete. A mid-stream event: error or a connection close before message_stop is not a completed answer. For a retry, run only the second block with the same key and unchanged body; a new key may start another paid generation. See streaming for recovery and protocol differences.

Count before generation

Send the same model and messages to POST /v1/messages/count_tokens before a generation:

bash
printf 'x-api-key: %s\n' "$API_KEY" \
  | curl -q -H @- -i "$BASE_URL/v1/messages/count_tokens" \
    -H "anthropic-version: 2023-06-01" \
    -H "Content-Type: application/json" \
    -d '{
  "model": "gpt-5.6-sol",
  "messages": [
    {
      "role": "user",
      "content": "Count this message."
    }
  ]
}'

HTTP 200 returns JSON with a numeric input_tokens, for example {"input_tokens":12}; the estimate depends on the input. This call starts no generation, but it does count toward the organization's requests per minute limit. The response also includes remaining-request rate limit headers. If the model catalog or plan rejects the call, check models and limits.

Next: authentication and errors.