API reference

Create message

POST /v1/messages generates the next assistant message for a conversation in the Anthropic Messages format, as JSON or as a stream. It is the endpoint Claude Code and the Anthropic SDKs call.

On this page
POSThttps://api.larasrouter.com/v1/messages

Generates the next assistant message for a conversation, in the Anthropic Messages format. This is the endpoint Claude Code and the Anthropic SDKs call. It runs the same model at the same prices as chat completions.

Authentication
Send the key in either header:Authorization: Bearer lr_live_…x-api-key: lr_live_…
Content type
application/json

This is the Anthropic Messages API, so Claude Code and the official Anthropic SDKs work with a change of base URL and key. It runs the same model as chat completions, at the same prices, with the same limits, and is billed from the usage the model reports. To connect Claude Code, follow the Claude Code guide.

The Anthropic SDKs add /v1/messages to the base URL themselves, so give them https://api.larasrouter.com without /v1. Errors from this endpoint use the Anthropic error envelope, not the OpenAI one.

Request body

  • modelstringrequired

    Model ID. Send deepseek-flash, not a Claude model name. A trailing [1m] is ignored.

  • max_tokensintegerrequired

    Output cap, 1 to 384,000. Required, as in the Anthropic API. A larger value is rejected, never silently reduced. Reasoning tokens count toward it.

  • messagesarrayrequired

    The conversation so far, oldest first. Each message has a role of user or assistant and content as a string or an array of blocks: text, tool_use, tool_result, and thinking. Image and document blocks are rejected.

  • systemstring | array

    The system prompt, as a string or an array of text blocks.

  • streamboolean

    Send the response as Server-Sent Events. Defaults to false.

  • toolsarray

    Tools the model may call: {name, description, input_schema}. Tools that run on Anthropic’s servers, such as web search, are ignored.

  • tool_choiceobject

    {"type": "auto"}, "any", "none", or {"type": "tool", "name": …}.

  • thinkingobject

    {"type": "enabled"} or {"type": "disabled"} turns reasoning on or off; budget_tokens is ignored. deepseek-flash reasons by default.

  • output_configobject

    {"effort": "low" | "medium" | "high" | "xhigh" | "max"} sets the reasoning effort.

  • temperature, top_p, stop_sequences, metadata—

    Sampling parameters and metadata.user_id, forwarded to the model. top_k and cache_control are accepted and ignored.

Example request

curl https://api.larasrouter.com/v1/messages \
  -H "x-api-key: $LARAS_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-flash",
    "max_tokens": 1024,
    "system": "You are a concise assistant.",
    "messages": [
      {"role": "user", "content": "Name three uses of a hash map."}
    ]
  }'

Response body

  • idstring

    Message ID, msg_ followed by the billing request ID.

  • typestring

    Always message.

  • rolestring

    Always assistant.

  • modelstring

    The model that answered.

  • contentarray

    The answer as blocks, in order: an optional thinking block with the model’s reasoning, then text and tool_use blocks.

  • stop_reasonstring

    end_turn, max_tokens (output cap reached), or tool_use.

  • usageobject

    Token counts the charge is computed from.

    • input_tokensinteger

      Input tokens that were not served from cache. As in the Anthropic API, cached tokens are not included.

    • cache_read_input_tokensinteger

      Input tokens served from cache, billed at the cache-hit rate.

    • cache_creation_input_tokensinteger

      Always 0.

    • output_tokensinteger

      Output tokens, reasoning included.

200 OK
{
  "id": "msg_0f8fad5bd9cb469fa16570867728950e",
  "type": "message",
  "role": "assistant",
  "model": "deepseek-flash",
  "content": [
    { "type": "thinking", "thinking": "The user wants three uses…", "signature": "lr1-…" },
    { "type": "text", "text": "1. Caching results by key…" }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 24,
    "output_tokens": 180,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0
  }
}

The thinking block carries the model’s reasoning, which is billed as output. Send it back unchanged on the next turn of a conversation that uses tools: the model requires its earlier reasoning to continue a tool conversation. The signature is an opaque value; Laras Router does not verify it on the way back.

Tool use

Declare tools in tools. When the model calls one, the reply has stop_reason: "tool_use" and a tool_use block with an id, a name, and an input object. Run the tool and send the result in the next user message as a tool_result block that carries the same tool_use_id.

Streaming

With "stream": true the response is a stream of Anthropic events: message_start, then content_block_start, content_block_delta and content_block_stop for each block, ping while the model is busy, and finally message_delta and message_stop. Tool input arrives as input_json_delta fragments that concatenate into the input object.

message_delta carries the stop reason and the final usage. It and message_stop are sent only after the request’s usage has been recorded, so a client that has seen message_stop knows the charge is final. If the stream is cut short, it ends with an error event and no message_stop.

text/event-stream
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","type":"message","role":"assistant","model":"deepseek-flash","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"1. Caching"}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":24,"output_tokens":180,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}

event: message_stop
data: {"type":"message_stop"}

What is not supported

  • Image and document blocks are rejected with 400 invalid_request_error, because the model takes text only.
  • Tools that run on Anthropic’s servers, such as web search, are ignored. Your own tools work.
  • POST /v1/messages/count_tokens is not available. Claude Code falls back to an estimate.
  • top_k, cache_control, and budget_tokens are accepted and ignored.

Errors

Errors use the Anthropic envelope, with the type your SDK expects:

Error response
{
  "type": "error",
  "error": {
    "type": "billing_error",
    "message": "Insufficient balance. Top up to continue."
  },
  "request_id": "req_0f8fad5bd9cb469fa16570867728950e"
}

request_id is the billing identity of the request, present once the request reached billing. Branch on error.type and the HTTP status; the message is in English by default and in Bahasa Indonesia when the request carries Accept-Language: id. See Errors & retries.

Responses

200The message: a JSON object, or an SSE stream of Messages events when stream is true.
application/jsontext/event-stream
  • X-Laras-Request-ID string — Billing identity of the request (UUID). Quote it when you contact support about a charge.
400The request is invalid (invalid_request_error): a missing max_tokens, an image or document block, or an output cap above the model’s. The message names the part of the request that was refused. Nothing was held or charged.
application/json
401The key is missing, malformed, revoked, or unknown, or Authorization and x-api-key carry different keys (authentication_error).
application/json
402The wallet or the key budget cannot cover the request (billing_error). Rejected before the model is called; nothing is held.
application/json
403The key lacks the chat:write scope (permission_error).
application/json
404The model is not served (not_found_error). Claude Code sends Claude model names unless you set ANTHROPIC_MODEL; use deepseek-flash.
application/json
413The request body is larger than 16 MB (request_too_large).
application/json
429A per-key limit was hit (rate_limit_error). Wait for Retry-After.
application/json
  • Retry-After integer — Seconds to wait before retrying.
502The model provider failed or could not be reached (api_error). Retry with backoff.
application/json
503Billing is temporarily unavailable; the request was not run (api_error). Retry later. You were not charged.
application/json