Messages format
POST /v1/messages: the same models in the Anthropic SDK format.
On this page
The API speaks the OpenAI and Anthropic SDK formats. This page is the Anthropic one: POST https://api.dipoleml.com/v1/messages. Keys, credits, prices and limits are the same as for Chat Completions.
Make a request
curl
curl https://api.dipoleml.com/v1/messages \ -H "x-api-key: $RAVEN_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "Raven Max", "max_tokens": 1024, "system": "You are a concise technical editor.", "messages": [{"role": "user", "content": "Tighten this paragraph: ..."}] }'python
import osfrom anthropic import Anthropicclient = Anthropic( base_url="https://api.dipoleml.com", api_key=os.environ["RAVEN_API_KEY"],)message = client.messages.create( model="Raven Max", max_tokens=1024, system="You are a concise technical editor.", messages=[{"role": "user", "content": "Tighten this paragraph: ..."}],)print(message.content[0].text)The SDK's base URL is https://api.dipoleml.com, without /v1: the SDK adds the path itself. The key goes in x-api-key, or as Authorization: Bearer (the SDK's auth_token).
{ "id": "msg_<request id>", "type": "message", "role": "assistant", "model": "Raven Max", "content": [{"type": "text", "text": "..."}], "stop_reason": "end_turn", "stop_sequence": null, "usage": { "input_tokens": 412, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "output_tokens": 96 }}idismsg_followed by the request id, which is also in therequest-idandx-request-idheaders.input_tokensleaves out cached input, which is counted incache_read_input_tokensand billed at the cached price.cache_creation_input_tokensis always0: caching needs no setup, andcache_controlmarks are accepted and not needed.stop_reasonisend_turn,max_tokens,stop_sequence(with the sequence instop_sequence),tool_useorrefusal.
Request fields
| Field | Notes |
|---|---|
model | Required. Raven Flash or Raven Max, in any letter case (Models). |
messages | Required, not empty. Roles user and assistant; content is a string or a list of blocks. |
max_tokens | A positive whole number: the most tokens the answer may use, reasoning included. |
system | A string or a list of text blocks. |
temperature, top_p, top_k | Sampling fields. |
stop_sequences | A list of strings. |
stream | true for an event stream (below). |
tools, tool_choice | Your own tools (Tool calling). |
thinking, output_config.effort | Reasoning (below). |
metadata is accepted and not used. A system message inside messages is accepted too: before the first turn it joins the system prompt; later, it is kept in place as a note to the model.
Content blocks
text.image, whosesourceis{"type": "base64", "media_type": "image/png", "data": "..."}or{"type": "url", "url": "https://..."}(Vision).tool_usein assistant turns andtool_resultin user turns, withis_errorwhen your tool failed.thinkingblocks from earlier answers may be sent back. Only those of the current tool loop are passed to the model.
A block type the API does not take is refused with 400 and a message that names it.
Thinking and effort
output_config.effort sets how much the model reasons: low and medium give a low level, high (or leaving it out) the default level, xhigh and max the highest. You may also send the OpenAI-format field reasoning_effort (Reasoning); it takes the lead when both are sent.
The model's reasoning comes back only when you ask for it with "thinking": {"type": "enabled"} or {"type": "adaptive"}, and not with "display": "omitted". It is then the first block of the answer:
[ {"type": "thinking", "thinking": "The user wants...", "signature": "rvn_<request id>"}, {"type": "text", "text": "..."}]The signature is an opaque string. Send the block back unchanged in a tool loop. budget_tokens is accepted; max_tokens is what bounds the answer.
Streaming
With "stream": true the answer is an event stream in the Anthropic SDK's order: message_start, ping, then for each block content_block_start, its content_block_delta events and content_block_stop, then message_delta with the stop_reason and the final usage, and message_stop.
event: message_startdata: {"type":"message_start","message":{"id":"msg_<request id>","type":"message","role":"assistant","model":"Raven Max","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":410,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0}}}event: pingdata: {"type":"ping"}event: content_block_startdata: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}event: content_block_deltadata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Caching keeps"}}event: content_block_stopdata: {"type":"content_block_stop","index":0}event: message_deltadata: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":412,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":96}}event: message_stopdata: {"type":"message_stop"}- The
input_tokensinmessage_startis an estimate; the count inmessage_deltais the one that is billed. - Deltas are
text_delta,thinking_deltaandsignature_delta(for a thinking block), andinput_json_delta(for a tool call). - While the model reasons and you did not ask to see it,
pingevents keep the connection open. - If the answer stops before it finishes, the stream ends with an
errorevent of typeapi_errorand nomessage_stop.
with client.messages.stream( model="Raven Flash", max_tokens=1024, messages=[{"role": "user", "content": "Explain caching in three sentences"}],) as stream: for text in stream.text_stream: print(text, end="", flush=True)Counting tokens
POST /v1/messages/count_tokens takes the same body and answers {"input_tokens": ...}. It is a rough estimate, made without calling the model; it needs a valid key and is not billed.
Errors
Errors have the Anthropic SDK's shape:
{ "type": "error", "error": { "type": "authentication_error", "message": "Missing API key. Send it in the 'x-api-key' header or as 'Authorization: Bearer <your key>'. Create one at https://dashboard.dipoleml.com/keys", "code": "missing_api_key" }}A bad key is refused before anything else about the request is checked. Errors and limits lists every status, type and code.