Skip to content

API reference

Anthropic-compatible API

A drop-in for Anthropic's Messages API, so Claude Code and anything built on Anthropic's SDKs runs on FullsendAI models by setting the base URL to https://fullsendai.com.

Overview#

Base URLhttps://fullsendai.com (the SDKs add /v1/messages)
Authenticationx-api-key: $FULLSEND_API_KEY or Authorization: Bearer. anthropic-version and anthropic-beta are accepted; any value works.
EndpointsPOST /v1/messages, POST /v1/messages/count_tokens, GET /v1/models
ErrorsAnthropic's error shape and types. See Errors.

Create a message#

POST/v1/messages

Request body

modelstringrequired
A FullsendAI model ID from Models, not a Claude model name.
max_tokensintegerrequired
The most tokens to generate, at least 1. Lowered to the model's maximum output if higher.
messagesarrayrequired
Alternating user and assistant turns; content is a string or an array of content blocks.
systemstring | array
Instructions for the whole conversation: a string or an array of text blocks.
temperature, top_pnumber
Sampling controls, passed to the model.
stop_sequencesstring[]
Text that ends the answer. A match ends it with stop_reason: end_turn.
streamboolean
Send Anthropic's server-sent events. See Streaming.
toolsarray
Custom tools: name, description, input_schema. See Tool use.
tool_choiceobject
{"type": "auto"}, any, none, or {"type": "tool", "name": "…"}.

metadata and top_k are accepted and ignored; thinking and cache_control are supported. See What's different.

curl https://fullsendai.com/v1/messages \  -H "x-api-key: $FULLSEND_API_KEY" \  -H "anthropic-version: 2023-06-01" \  -H "Content-Type: application/json" \  -d '{    "model": "deepseek-v4.1-flash",    "max_tokens": 2048,    "system": "You are a senior Rust engineer. Answer with code first.",    "messages": [{"role": "user", "content": "Write a lock-free ring buffer"}]  }'
Response
{  "id": "msg_af2452aa21131e20bbdab2c9",  "type": "message",  "role": "assistant",  "model": "deepseek-v4.1-flash",  "content": [{ "type": "text", "text": "use std::sync::atomic::{AtomicUsize, Ordering}; …" }],  "stop_reason": "end_turn",  "stop_sequence": null,  "usage": { "input_tokens": 31, "output_tokens": 642 }}

Content blocks#

textuser, assistant
{"type": "text", "text": "…"}
imageuser
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "…"}}, or a source of {"type": "url", "url": "https://…"}. For models that read images; see Images.
tool_useassistant
A call the model made: id, name, input. Send it back unchanged in the history.
tool_resultuser
tool_use_id, content (a string or text blocks) and optional is_error.

Images inside a tool_result and thinking blocks in the history are dropped before the model sees them.

The response#

idstring
Unique per response, like msg_….
modelstring
The model ID you sent.
contentarray
text blocks, then tool_use blocks when the model called tools.
stop_reasonstring
end_turn (finished, or hit a stop sequence), max_tokens or tool_use.
stop_sequencenull
Always null.
usageobject
input_tokens and output_tokens, exactly as billed.

Streaming#

Events arrive in Anthropic's order: message_start, ping, then for each block content_block_start, content_block_delta (text_delta or input_json_delta) and content_block_stop, then message_delta with the stop reason and the token counts, and message_stop. The SDKs' stream helpers work as they do against Anthropic.

event: message_startdata: {"type":"message_start","message":{"id":"msg_2976…","type":"message","role":"assistant","model":"deepseek-v4.1-flash","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"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":"One, two,"}}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":8,"output_tokens":6}}event: message_stopdata: {"type":"message_stop"}

Token counts arrive in message_delta; message_start carries zeros. If the model stops answering part way, an error event ends the stream. See Streaming.

Tool use#

The model answers with a tool_use block and stop_reason: tool_use; you run the tool and send a tool_result. Walkthrough on Tool calling.

Python
tools = [{    "name": "run_tests",    "description": "Run the project's test suite and return the output",    "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]},}]question = {"role": "user", "content": "Fix the failing tests in src/parser"}first = client.messages.create(model="deepseek-v4.1-flash", max_tokens=1024, tools=tools, messages=[question])call = next(block for block in first.content if block.type == "tool_use")output = run_tests(**call.input)  # your codesecond = client.messages.create(model="deepseek-v4.1-flash", max_tokens=1024, tools=tools, messages=[    question,    {"role": "assistant", "content": first.content},    {"role": "user", "content": [{"type": "tool_result", "tool_use_id": call.id, "content": output}]},])

Count tokens#

POST/v1/messages/count_tokens

Takes the same body as /v1/messages and returns {"input_tokens": 20}. It's an estimate (about four characters a token over the system prompt, messages and tools), free and not rate limited; billing always uses the model's exact counts.

List models#

GET/v1/models

With an anthropic-version header, the list comes back in Anthropic's shape (data[].id, display_name, created_at, has_more). See Models.

What's different from Anthropic's API#

  • Model IDs are FullsendAI's (like deepseek-v4.1-flash), not Claude names. A Claude name gets 404 not_found_error.
  • Server tools (web search, code execution and the like) aren't run; custom tools with an input_schema work as usual.
  • Extended thinking: thinking: {type: "enabled", budget_tokens} sets the model's reasoning effort (under 4,096 tokens is low, under 16,384 medium, otherwise high); disabled turns it off. Reasoning comes back as thinking blocks, and as thinking_delta events when streaming.
  • Prompt caching: cache_control markers are passed to the model. Input read from the cache is reported as usage.cache_read_input_tokens (with input_tokens counting only the rest) and billed at the model's cached price.
  • Documents: base64 PDF blocks are read by models that accept files; a document given by URL, or one that isn't a PDF, gets a 400.
  • Batches, Files and the Admin API aren't served.
  • Errors on GET /v1/models use the OpenAI shape; /v1/messages and count_tokens use Anthropic's.

SDKs#

import osimport anthropicclient = anthropic.Anthropic(base_url="https://fullsendai.com", api_key=os.environ["FULLSEND_API_KEY"])
Using Claude Code? See Connect your agent: three environment variables and you're running.

Stuck? Email [email protected]System statusChangelog