POST /v1/messages speaks the Anthropic Messages request and response grammar. If your application already uses the Anthropic SDK, point it at RunInfra by changing two values, the base URL and the key, and leave the rest of your code alone.
The endpoint is a translation layer, not a separate inference path. Requests run through the same serving pipeline as POST /v1/chat/completions, so billing, prepaid credit settlement, idempotent retries, rate limits, request limits, and cached input pricing all behave exactly as they do there.
Authentication
Send your RunInfra API key in either header on this endpoint. Both accept the same keys.
If both are present,
x-api-key wins.
x-api-key is accepted on /v1/messages only. Every other endpoint, including GET /v1/models, takes Authorization: Bearer, so an Anthropic client’s models.list() will not authenticate. List the model ids your key can reach with a Bearer request instead:anthropic-version is accepted and echoed back on the response. It does not select a behavior: this endpoint publishes one grammar, described on this page.
Minimal request
The Anthropic SDK appends
/v1 itself, so base_url is the bare host, https://api.runinfra.ai. The OpenAI SDK does not, which is why the /v1/chat/completions examples elsewhere in these docs use https://api.runinfra.ai/v1.Request fields
Content blocks
A message’scontent is a string, or an array of {"type":"text","text":"..."} blocks. Multiple text blocks, in system or in a message, are concatenated in order with no separator inserted: nothing you did not write is added, and nothing you wrote is dropped.
An empty or whitespace-only system value means no system prompt, and no system turn is sent to the model.
Response
stop_reason is derived from how generation ended:
stop_sequence is always null on this endpoint. Your stop_sequences are still honored by the model, but the matched sequence is not reported back, so we return null rather than name a sequence we did not measure.
usage.input_tokens is the full prompt token count, including any part served from a cached prefix, and it is exactly what the request was billed on. This endpoint does not report cache_read_input_tokens or cache_creation_input_tokens, so unlike Anthropic there is nothing to add to input_tokens to get the total. Cached input pricing still applies, and is visible on POST /v1/chat/completions and in your usage dashboard.
Streaming
Setstream: true to receive Server-Sent Events in the Anthropic event grammar. The Anthropic SDK’s client.messages.stream(...) works unchanged.
message_startreports zero usage. The prompt token count is not known until generation ends, and we would rather send a zero you can see than a number we guessed. The authoritative counts arrive onmessage_delta, which is where the Anthropic SDK’s own stream accumulator takes final usage from, sostream.finalMessage()reports the right totals.message_delta.usage.input_tokenscan benullin the rare case the upstream reported no usage at all. It is never a stand-in zero.
error event and no message_stop:
APIError, keyed on error.type.
Errors
Every4xx and 5xx uses the Anthropic error envelope, including refusals raised before the model is reached:
request_id also rides on the x-request-id response header. Quote it in any support request.
Idempotent retries
Send anIdempotency-Key header exactly as you would on POST /v1/chat/completions. The key is bound to the Anthropic request body you sent, so retrying the same Messages request replays the original outcome instead of running and billing a second generation. See Idempotent retries.
What this endpoint does not do
Each of these answers a400 that names the field. Nothing is dropped silently.
Two behaviors also differ from Anthropic and are worth planning around:
- Reasoning is not returned, but it is still generated and still billed. Anthropic’s carrier for reasoning is a
thinkingblock, and both the block and its streamed form require a cryptographicsignatureover the reasoning text that only Anthropic can issue. Rather than ship an empty or invented signature, this endpoint returns the answer alone. The reasoning still spends yourmax_tokens, so a small budget can be used up thinking and return an emptycontentarray withstop_reason: "max_tokens", billed for those output tokens. Give the models room, or use Chat completions where both channels are visible. - Consecutive same-role turns are not merged. Anthropic combines consecutive
userorassistantturns into one before the model sees them. This endpoint forwards your turns exactly as written, so a model that rejects a non-alternating conversation gives you a clear error rather than a prompt we quietly rewrote.
Related
Chat completions
The OpenAI-shaped endpoint, with tools.
Streaming
The OpenAI-shaped stream, delta by delta.
List models
The model ids your key can reach.