Bineric APIdocumentation

One OpenAI-compatible API for Lynx and models from OpenAI, Anthropic, Google and more, and Zuse for decisions. Change the base URL in your OpenAI SDK and keep your code.

Get an API key

For agents and LLM tools: docs.md · llms.txt

Chat, images, speech and research

OpenAI-compatible. Keep your OpenAI SDK and change the base URL.

POST /v1/chat/completions

Quickstart →

Decisions with Zuse

Its own endpoint and format, Jev's rather than OpenAI's. Answers with how sure it is.

POST /v1/zuse

How it differs →Zuse quickstart →

Base URL
https://api.bineric.com/v1
Auth
Authorization: Bearer
Format
OpenAI-compatible, Zuse
Models
41 chat, image and audio
On this page

Getting started

Quickstart

The Bineric API is OpenAI-compatible. Point an OpenAI SDK at the Bineric base URL, use a Bineric API key, and call any model in the list below.

Base URL

Chat completions and the model list live under /v1, where OpenAI SDKs expect them. Account endpoints (file conversion, usage and balance) live under /api/v1. The older /api/v1/ai/chat/completions still works for chat completions.

bash
https://api.bineric.com/v1

First request

To switch models, change model to any id from Models. Everything else stays the same.

from openai import OpenAI
client = OpenAI(
base_url="https://api.bineric.com/v1",
api_key="YOUR_API_KEY",
)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

Getting started

Authentication

Every request except the model list (GET /v1/models and GET /v1/models/{model}) needs an API key.

Send the key as a Bearer token in the Authorization header (what the OpenAI SDKs do), or in an api-key header. If both are sent, the Bearer token is used.

bash
-H "Authorization: Bearer YOUR_API_KEY"
# or
-H "api-key: YOUR_API_KEY"

Get a key

  1. Create an account at platform.bineric.com.
  2. Create an API key in the dashboard and copy it.
  3. Buy credits under Billing. A call needs a completed purchase and a balance of at least $0.10; a saved card on its own is not enough.

Getting started

Models

Pass the id in the first column as model. Prices are in USD, at the provider's list price.

Language models · 35

modelProviderContextIn / out per 1MSupports
lynx-30bLynx · hosted in EUBineric AI262K$3 / $15
gpt-4oGPT-4o · hosted in EUOpenAI128K$2.50 / $10ToolsVision
gpt-5GPT-5-Reasoning · hosted in EUOpenAI128K$1.38 / $11ToolsVision
gpt-5-miniGPT-5-Mini · hosted in EU, USOpenAI128K$0.25 / $2ToolsVision
gpt-5.1GPT 5.1 · hosted in EU, USOpenAI400K$1.25 / $10ToolsVision
gpt-5.2GPT 5.2 · hosted in USOpenAI400K$1.75 / $14ToolsVision
gpt-5.3GPT 5.3 · hosted in USOpenAI128K$1.75 / $14ToolsVision
gpt-5.4GPT 5.4 · hosted in EUOpenAI1M$2.75 / $16.50ToolsVision
gpt-5.5GPT-5.5 · hosted in EUOpenAI1M$5.50 / $33ToolsVision
gpt-5.6-lunaGPT-5.6-Luna · hosted in EUOpenAI1M$0.22 / $1.32Vision
gpt-5.6-solGPT 5.6 Sol · hosted in EUOpenAI1M$4.40 / $22Vision
gpt-5.6-terraGPT 5.6 Terra · hosted in EUOpenAI1M$2.20 / $13.20Vision
gpt-oss-20bgpt-oss-20b · hosted in USOpenAI128K$0.07 / $0.30
gpt-oss-120bgpt-oss-120b · hosted in USOpenAI128K$0.15 / $0.60
o1O1 · hosted in EUOpenAI128K$15 / $60ToolsVision
o3-miniO3-Mini · hosted in EUOpenAI128K$1.10 / $4.40ToolsVision
claude-haiku-4-5Claude Haiku 4.5 · hosted in EUAnthropic200K$1.10 / $5.50ToolsVision
claude-haiku-5.5Claude Haiku 5.5 · hosted in EUAnthropic80K$0.11 / $0.55ToolsVision
claude-opus-4-5Claude Opus 4.5 · hosted in EUAnthropic200K$5.50 / $27.50ToolsVision
claude-opus-4-6Claude Opus 4.6 · hosted in EUAnthropic1M$5.50 / $27.50ToolsVision
claude-opus-4-7Claude Opus 4.7 · hosted in EUAnthropic1M$5.50 / $27.50ToolsVision
claude-opus-4.8Claude Opus 4.8 · hosted in EUAnthropic1M$5.50 / $27.50ToolsVision
claude-opus-5Claude Opus 5 · hosted in EUAnthropic1M$5.50 / $27.50Vision
claude-opus-5.5Claude Opus 5.5 · hosted in EUAnthropic1M$4.40 / $22Vision
claude-sonnet-4-6Claude Sonnet 4.6 · hosted in EUAnthropic1M$3.30 / $16.50ToolsVision
claude-sonnet-5Claude Sonnet 5 · hosted in EUAnthropic1M$2.20 / $11Vision
claude-sonnet-5.5Claude Sonnet 5.5 · hosted in EUAnthropic1M$2.20 / $11Vision
gemini-2.5-flashGemini-2.5-Flash · hosted in USGoogle1M$0.30 / $2.50ToolsVision
gemini-2.5-proGemini-2.5-Pro · hosted in USGoogle1M$1.25 / $10ToolsVision
gemini-3-pro-previewGemini-3-Pro · hosted in USGoogle1M$1.25 / $10ToolsVision
borealis-2Borealis 2 · hosted in EUNasjonalbiblioteket16K$2 / $10
meta-llama-3.3-70bLlama 3.3-70B · hosted in USMeta128K$0.72 / $0.72
mistral_large_24_02Mistral Large 24.02 · hosted in EUMistral AI32K$4.30 / $13
qwen-3-235bQwen 3 235B · hosted in EUQwen128K$0.22 / $0.88
qwen-3-coder-480bQwen 3 Coder 480B · hosted in EUQwen128K$0.45 / $1.80

Image models · 3

modelProviderContextPriceSupports
gpt-image-1gpt-image-1 · hosted in EUOpenAI128K$10 / $40Vision
nano-banana-2Nano Banana 2 · hosted in USGoogle128K$0.50 / $61
stability-aiStable Diffusion 3.5 Large · hosted in USStability AI–$0.08 per image

Speech, search and research models · 3

modelProviderContextPriceSupports
deep-researchDeep Research · hosted in USBineric AI128K$0.25 per call
speech-to-textSpeech to Text · hosted in EUMicrosoft4K$0.18 per hour
sonar-web-searchsonar-web-search · hosted in USPerplexity128K$1 / $1

Retired ids still work and are answered by their replacement: claude-sonnet-4 → claude-sonnet-4-6.

Decision models (Zuse) answer fixed-choice questions through their own endpoint; see the Zuse API. The model library compares every model side by side.

GET /v1/models

GET/v1/models

Every model the API serves, chat and decision models together, with live prices. No key is needed, and client.models.list() works. Per-token prices are per million tokens; per_request is a fixed price per call (0 when there is none), and decision models show per_decision instead. For speech-to-text, per_request is the price per hour of speech. The text-to-speech model works but is not in this list. models repeats the decision models with their name and description.

owned_by is the provider the model runs on. hosting is EU, US or Both. context_length is the model's context window in tokens.

bash
curl https://api.bineric.com/v1/models
json
{
"object": "list",
"data": [
{
"id": "claude-sonnet-4-6",
"object": "model",
"created": 1735689600,
"owned_by": "bedrock-anthropic",
"name": "Claude Sonnet 4.6",
"description": "Claude Sonnet 4.6 delivers frontier intelligence at scale, built for coding, agents, and enterprise workflows.",
"category": "General",
"hosting": "EU",
"tier": "premium",
"context_length": 1000000,
"pricing": {
"input_per_million_tokens": 3.3,
"output_per_million_tokens": 16.5,
"per_request": 0,
"currency": "USD"
}
}
],
"models": []
}

GET /v1/models/{model}

GET/v1/models/{model}

One model by id, with the same fields as its entry in the list. No key is needed, and client.models.retrieve("zuse-27b") works. An unknown id returns 404 model_not_found.

bash
curl https://api.bineric.com/v1/models/zuse-27b
json
{
"id": "zuse-27b",
"object": "model",
"created": 1793025018,
"owned_by": "bineric",
"name": "Zuse 27B",
"description": "Typed decisions with calibrated probabilities in 115 languages, hosted in the EU.",
"category": "Decision",
"hosting": "EU",
"tier": "premium",
"context_length": 65536,
"pricing": {
"input_per_million_tokens": 0.75,
"output_per_million_tokens": 0,
"per_decision": 0,
"currency": "USD"
}
}

Zuse API

How Zuse differs

Zuse uses the same API key, base URL and credit as the rest of the API, but not the OpenAI format. It has its own endpoint, request and answer: Jev's format, not chat.

Endpoint
ChatPOST /v1/chat/completionsZusePOST /v1/zuse
You send
ChatmessagesZuseA document (state) and your questions
You get back
ChatGenerated textZuseA choice, a yes or no, or a score, with how sure it is
Client
ChatThe OpenAI SDK, pointed at our base URLZuseAny HTTP client, or TypeSafe's Jev SDKs
Models
ChatThe model listZusezuse-27b (Decision models)
List models
ChatGET /v1/modelsZuseThe same GET /v1/models: one list for both, where Zuse models have category: "Decision"
You pay for
ChatInput and output tokensZuseInput tokens only
Rate limit
Chat500 requests a minute per IP addressZuse1,200 requests a minute per key

Sending a decision model to chat completions, or a chat model to /v1/zuse, returns 400 model_not_supported. New to Zuse? Start with the Zuse quickstart, or try it without a key in the playground.

Zuse API

Zuse quickstart

Zuse reads a document and answers your questions with a choice, a yes or no, or a score, and says how sure it is. Hosted in the EU.

POST/v1/zuse

The examples read your key from an environment variable, so set it first: export BINERIC_API_KEY=your_key. The Python example needs pip install requests. Save the JavaScript example as a .mjs file, because it uses top-level await.

Send the document as state and your questions as questions, keyed by ids you choose. Every question about one document is answered in a single pass, and the answers come back under the same ids.

curl https://api.bineric.com/v1/zuse \
-H "Authorization: Bearer $BINERIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "zuse-27b",
"state": "Hi, I was charged twice for my monthly pass last week. I want my money back as soon as possible, this is the second time it has happened!",
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle it?",
"criteria": {
"billing": "Payments and refunds",
"technical": "The app or website is not working",
"travel": "Questions about routes and departures",
"other": "Other"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
},
"urgency": {
"type": "score",
"instructions": "How urgent is it?",
"criteria": [
"Not urgent",
"Normal",
"Urgent",
"Critical"
]
}
}
}'

Request body

FieldTypeDescription
modelstringOptional. A decision model id; see Decision models.
statestring, object or arrayThe document or record to decide about. JSON is passed as is; you do not need to flatten it.
questionsobjectAt least one question, keyed by an id you choose. See Question types.
json
{
"model": "zuse-27b",
"state": "Hi, I was charged twice for my monthly pass last week. I want my money back as soon as possible, this is the second time it has happened!",
"questions": {
"team": {
"type": "choice",
"instructions": "Which team should handle it?",
"criteria": {
"billing": "Payments and refunds",
"technical": "The app or website is not working",
"travel": "Questions about routes and departures",
"other": "Other"
}
},
"refund": {
"type": "noul",
"instructions": "Is the customer asking for a refund?"
},
"urgency": {
"type": "score",
"instructions": "How urgent is it?",
"criteria": [
"Not urgent",
"Normal",
"Urgent",
"Critical"
]
}
}
}

Zuse API

Decision models

Pass the id as model, or leave it out and the request goes to zuse-27b.

modelUse it forContextPrice
zuse-27bZuse 27B · hosted in EUHighest accuracy, for the decisions you automate.66K$0.75 per 1M input tokens

Zuse 9B is not on the Bineric API, so zuse-9b returns 404 here. It runs in your own cloud account: get it from AWS Marketplace. Azure is coming soon.

You pay per input token. Zuse writes no text, so there are no output tokens to pay for. Decision models are also listed by GET /v1/models, with category set to Decision. Chat models sent to /v1/zuse return 400 model_not_supported.

Zuse API

Question types

Every question takes type and instructions: the question itself, in any language.

typecriteriaWhat you get
choiceObject of option id to description, 1 to 255 options. A description can be null.choice (the most likely option id), confidence, and probabilities for every option.
noulNone. State the yes/no question in instructions.noul: the probability that the answer is yes.
scoreArray of levels in order, lowest first. Use at least 2: a single level is accepted and billed, but tells you nothing.score (the expected level, counted from 0), confidence, legend and probabilities per level.

What confidence means

confidence is not the top probability. It is rescaled so that 0 means the model cannot tell the options apart and 1 means it is certain, however many options you give it. With two options and a top probability of 0.95, confidence is 0.90.

  • choice: (p_max - 1/K) / (1 - 1/K), where p_max is the top probability and K the number of options. With one option it is 1.
  • score: max(0, 1 - E|level - mode| / D), where mode is the most likely level and D is the average distance from the middle of the scale. It is 1 when all the probability is on one level and 0 when it is spread evenly.
  • noul has no confidence field: it is the probability of yes, so a low value is a confident no. On the same scale as confidence, use |2 * noul - 1|.

Zuse API

Response

The answers, keyed by your question ids, with the tokens you are billed for.

The values here are an example. usage.input_tokens is what you are billed for. usage.output_tokens is reported for information: Zuse models are priced on input tokens. latency_ms is model time, without the network.

json
{
"model": "zuse-27b",
"answers": {
"team": {
"type": "choice",
"choice": "billing",
"confidence": 0.9883,
"probabilities": {
"billing": 0.9912,
"technical": 0.0031,
"travel": 0.0009,
"other": 0.0048
}
},
"refund": {
"type": "noul",
"noul": 0.9874
},
"urgency": {
"type": "score",
"score": 2.3001,
"legend": {
"0": "Not urgent",
"1": "Normal",
"2": "Urgent",
"3": "Critical"
},
"probabilities": {
"0": 0.0102,
"1": 0.0915,
"2": 0.4863,
"3": 0.412
},
"confidence": 0.4761
}
},
"usage": {
"input_tokens": 214,
"output_tokens": 209
},
"latency_ms": 18.6
}

Response headers

HeaderMeaning
x-bineric-modelThe model that answered.
x-bineric-hostingWhere it ran, for example EU.

Zuse API

Errors and limits

Errors use the same OpenAI shape as the rest of the API, plus detail, where clients written for Jev look for the message.

json
{
"error": {
"message": "`questions` must contain at least one question.",
"type": "invalid_request_error",
"code": "invalid_request"
},
"detail": "`questions` must contain at least one question."
}
StatuscodeMeaning
400invalid_requestThe body is a JSON array, or questions is missing, empty or not an object.
400–The body is neither a JSON object nor an array, for example invalid JSON or a bare string. The parser refuses it before the API key is checked, in its own shape: {"success":false,"error":"...","message":"...","requestId":"..."}, without code or detail. A zstd-compressed body gets invalid_request in these cases instead.
400model_not_supportedA chat model was sent. Use a decision model.
401missing_api_key, invalid_api_keyNo key, or the key is wrong or disabled.
402insufficient_quotaNot enough credit. Buy credits.
403payment_requiredThis model needs credit on the account. Buy credits.
404model_not_foundUnknown model id. The message lists the decision models.
400, 413, 422–The decision server rejected the request, for example a malformed question or a document that is too long. Its body comes back as it was sent.
429rate_limit_exceededToo many requests. Slow down and retry.
502, 503, 504upstream_error, upstream_unavailable, server_busy, model_not_available, upstream_timeoutRetry with backoff. Failed requests are not billed.

Limits

  • 1,200 requests a minute per API key, and 2,400 a minute per IP address. These are separate from the chat limits.
  • The document and questions must fit the model's context length, context_length in GET /v1/models.
  • Up to 255 options per choice question.

Zuse API

Using the probabilities

Act on the sure answers and send the rest to a person.

  • Set a threshold per question and send anything below it to a person. On our European suite, 77.2% of the 27B model's answers clear the threshold that keeps errors under 5%.
  • Add a "none of these" option to choice questions whose answer may not be in the list. The model is trained to pick it when nothing fits.
  • Routing, reading comprehension and entailment automate well. Keep legal interpretation, grammar judgements and questions that need world knowledge review-first.

Zuse API

Moving from Jev

Code written for Jev, including TypeSafe's Python and JavaScript SDKs, runs on Zuse with a new base URL and key.

  • Install TypeSafe's Python SDK with pip install typesafe-sdk. For the JavaScript SDK, see TypeSafe's own documentation.
  • POST /v1/systemone, Jev's path, works the same as POST /v1/zuse.
  • Jev model names, such as jev-latest, are answered by Zuse 27B.
  • Bodies compressed with zstd (Content-Encoding: zstd), as the SDKs send them, are accepted.
  • Choice, yes/no and score questions are supported. Image (box) questions are not.

How the two compare: Zuse, the European Jev alternative.

diff
- TYPESAFE_BASE_URL=https://api.typesafe.ai
+ TYPESAFE_BASE_URL=https://api.bineric.com
- TYPESAFE_API_KEY=your-typesafe-key
+ TYPESAFE_API_KEY=your-bineric-key
TYPESAFE_DEFAULT_MODEL=jev-latest

Chat

Chat completions

Generate a response from a list of messages, in the OpenAI format.

POST/v1/chat/completions

Request body

FieldTypeDescription
modelstringRequired. A model id from Models.
messagesarrayRequired. The conversation so far; see Messages below.
streambooleanStream the response as server-sent events. Default false. See Streaming.
stream_optionsobject{"include_usage": true} adds a final chunk with token usage.
max_completion_tokensintegerMaximum tokens in the response, never above the model's own output limit. max_tokens also works.
temperaturenumber0 to 2. Out of range returns 400.
top_pnumber0 to 1. Out of range returns 400.
reasoning_effortstringlow, medium or high; minimal, none, xhigh and max are also accepted. Used by models that reason; other values are ignored.
toolsarrayFunctions the model may call. See Tool calling.
tool_choicestring or objectauto, none, required, or {"type":"function","function":{"name":"..."}}.
parallel_tool_callsbooleanSent to OpenAI and Qwen models; others ignore it.

GPT-5 and the o-series ignore temperature and top_p, and so do Claude Opus 4.7 and later, Claude Sonnet 5, and any Claude request with reasoning on. Other Claude models use one of the two: temperature if both are sent. reasoning_effort: "none" picks the lowest level the model has, which on older Claude models and Gemini 2.5 Flash turns reasoning off.

Older integrations can still send stream, temperature, top_p and reasoning_effort inside an options object, and max_response_length at the top level. Top-level fields win when both are sent.

Messages

FieldTypeDescription
rolestringsystem, user, assistant or tool.
contentstring or arrayThe text, or an array of content parts (below). Can be null on an assistant message that only has tool_calls.
tool_callsarrayAssistant messages only: the tool calls the model made, sent back unchanged.
tool_call_idstringTool messages only: the id of the call this result answers.
attachmentsarrayBineric's own format: base64 data URLs. Content parts do the same thing.

Content parts

TypeDescription
text{"type": "text", "text": "..."}
image_urlimage_url.url is a base64 data URL or an http(s) URL. Images fetched from a URL can be up to 20 MB.
filefile.file_data is a base64 data URL; file.filename is optional. file_id is not supported.
input_audioinput_audio.data (base64) and input_audio.format (wav or mp3).

Images, files and audio are read from the last user message only; attach them to the message you are asking about. A malformed part returns 400 with param pointing at it, for example messages[0].content[1].

json
{
"model": "gpt-4o",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What is in this image, and what does the report say about it?" },
{ "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } },
{ "type": "file", "file": { "filename": "report.pdf", "file_data": "data:application/pdf;base64,JVBERi0..." } }
]
}
]
}

Files

KindFormatsNotes
ImagesJPEG, PNG, WebP, GIFModels that support vision. Each model has its own size limit (Claude: 3.75 MB); a larger image returns 400. Images are scaled to fit 1024×1024.
DocumentsPDF, DOCX, DOC, XLSX, XLS, TXT, CSV, MD, JSON, HTMLThe text is extracted and sent to the model.
AudioWAV, MP3Gemini models and speech-to-text only. Other models return 400.

Response

model in the response is the model's display name, such as GPT-4o, not the id you sent. finish_reason is stop, length (cut off by max_completion_tokens or the model's limit) or tool_calls; image models can also return content_filter.

When a model is retired, requests for its id are answered by its replacement, and model shows the replacement's name.

json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "GPT-4o",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Hello! How can I help?" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 9, "completion_tokens": 7, "total_tokens": 16 }
}

Chat

Streaming

Set stream: true to receive the response as server-sent events while it is written.

stream = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Write a haiku about the sea."}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")

Events

  • The first chunk carries the role, then come content chunks, then an empty delta with the finish_reason.
  • The usage chunk (empty choices) is only sent when the request sets "stream_options": {"include_usage": true}.
  • Reasoning models also send delta.reasoning_content chunks with their reasoning.
  • Search models add _bineric.citations to the last chunk.
  • If an error happens after the stream has started, it arrives as data: {"error": {...}} and the stream closes without [DONE].
text
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{"content":"Waves"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":17,"total_tokens":31}}
data: [DONE]

Tool calls

Tool calls stream as delta.tool_calls. The first piece of each call carries its id and function name; join the arguments strings by index.

Image, speech and deep research models do not send OpenAI chunks; see their sections.

text
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_abc123","type":"function","function":{"name":"get_weather","arguments":""}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":\"Oslo\"}"}}]},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1768818339,"model":"GPT-4o","choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}

Chat

Tool calling

Give the model functions it can call. The model returns the call; your code runs it and sends the result back.

The Supports column in Models marks the models that support tool calling (Tools). Image, audio, search and research models return 400 with code: "tools_not_supported" and param: "tools", both when tools is sent and when the messages carry earlier tool calls or results.

1. Send tools

Describe each function with a name, a description and a JSON Schema for its parameters. tool_choice: "auto" lets the model decide; "required" makes it call one.

json
{
"model": "gpt-4o",
"messages": [
{ "role": "user", "content": "What's the weather in Oslo?" }
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}
],
"tool_choice": "auto"
}

2. The model calls a tool

finish_reason is tool_calls and message.tool_calls holds the calls. arguments is a JSON string: parse it, then run your function.

json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "GPT-4o",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"Oslo\"}" }
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": { "prompt_tokens": 62, "completion_tokens": 18, "total_tokens": 80 }
}

3. Send the result back

Add the assistant message unchanged, then a tool message with the matching tool_call_id. Keep sending tools. The model then answers in text with finish_reason: "stop".

json
{
"model": "gpt-4o",
"messages": [
{ "role": "user", "content": "What's the weather in Oslo?" },
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": { "name": "get_weather", "arguments": "{\"city\":\"Oslo\"}" }
}
]
},
{ "role": "tool", "tool_call_id": "call_abc123", "content": "{\"temp_c\": 12, \"sky\": \"cloudy\"}" }
],
"tools": [ ... ]
}

Chat

Errors

Errors use the OpenAI shape, so SDKs raise their usual exceptions.

json
{
"error": {
"message": "temperature must be between 0 and 2",
"type": "invalid_request_error",
"param": "temperature",
"code": "invalid_request"
}
}
StatuscodeMeaning
400invalid_requestA field is wrong; param names it (for example temperature, tools[0].function.name or messages[0].content[1]).
400model_not_foundUnknown model id in a request. Use an id from GET /v1/models.
400model_not_supportedA decision model was sent to chat completions. Use POST /v1/zuse.
400tools_not_supportedThe model does not support tools.
400nullAn attachment is too large, of an unsupported type, or could not be processed.
401missing_api_key, invalid_api_keyNo key, or the key is wrong or disabled.
402insufficient_quotaBalance below $0.10. Buy credits.
403payment_requiredNo completed purchase on the account yet. Buy credits.
404model_not_foundGET /v1/models/{model} with an id that is not in the list.
404unknown_endpointNo such endpoint.
429rate_limit_exceededToo many requests from your IP address. Wait for Retry-After seconds.
429concurrent_request_limitToo many requests running at once on your account.
500internal_errorSomething failed on our side. Retry.
502image_generation_failedThe image model failed.
503model_not_configuredThe model is listed but not available right now. Try another model.

Errors from the model provider, such as its own rate limits or content policy, are passed through with the provider's status and code. Retry 429 and 5xx responses with exponential backoff.

Chat

Rate limits

  • 500 requests a minute per IP address across /v1 and /api/v1. Over the limit you get 429 with a Retry-After header and the standard RateLimit-* headers.
  • Up to 50 requests running at once per account; more return 429 concurrent_request_limit.
  • Each model's context window and output limit apply; see Models.

Images, speech and research

Image generation

Use an image model with chat completions. The last user message is the prompt.

POST/v1/chat/completions
  • gpt-image-1 also reads size, quality, output_format and n at the top level of the body.
  • Attach images to the last user message to edit them instead; _bineric.operation is then editing.
  • Image models do not stream. With stream: true you still get one JSON response, not events, so call them without streaming.
json
{
"model": "gpt-image-1",
"messages": [
{ "role": "user", "content": "A lighthouse on a rocky coast at dawn, watercolour" }
],
"size": "1024x1024",
"quality": "high"
}

Response

message.content holds each image as a Markdown image with a data URL. The raw data URLs are also in _bineric.images.

When Stable Diffusion or a Gemini image model blocks a prompt, you get 200 with a short text reply, finish_reason: "content_filter" and an empty _bineric.images. gpt-image-1 returns the provider's content policy error instead.

json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "gpt-image-1",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "![image 1](data:image/png;base64,iVBORw0KGgo...)" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
"_bineric": {
"images": ["data:image/png;base64,iVBORw0KGgo..."],
"image_count": 1,
"operation": "generation",
"total_cost": 0.04
}
}

Images, speech and research

Text to speech

Turn text into speech with the text-to-speech model. The last user message is the text.

POST/v1/chat/completions
FieldDefaultDescription
voicenb-NO-FinnNeuralAn Azure neural voice name, such as nb-NO-PernilleNeural, en-US-JennyNeural or sv-SE-SofieNeural. The voice decides the language you hear.
languagenb-NOThe locale of the text, such as en-US. Also accepted as locale. It does not choose a voice, so set voice too.
ratemediumSpeaking rate, as SSML prosody: slow, medium, fast or a percentage like +10%.
pitchmediumPitch, such as low, high or +5%.
volumeloudVolume, such as soft, medium or +20%.

Send these at the top level of the body. Norwegian voices: Finn (male), Iselin and Pernille (female). Voices for English, Swedish, Danish and other languages follow the same pattern, <locale>-<Name>Neural.

json
{
"model": "text-to-speech",
"messages": [{ "role": "user", "content": "Hei, velkommen til Bineric!" }],
"voice": "nb-NO-PernilleNeural",
"language": "nb-NO",
"rate": "medium"
}

Response

The speech is MP3 (16 kHz, 32 kbps, mono), base64-encoded in message.audio.data. It is priced at $16 per million characters.

Long text is split into chunks of up to 500 characters at sentence ends. If some chunks fail, you still get 200 with the audio that worked; compare processedChunks with totalChunks.

json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "Text to Speech",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"audio": { "data": "<base64 mp3>", "format": "mp3" }
},
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
"_bineric": {
"metadata": {
"language": "nb-NO",
"voice": "nb-NO-PernilleNeural",
"textLength": 27,
"format": "mp3",
"quality": "16khz/32kbps",
"processedChunks": 1,
"totalChunks": 1,
"settings": { "rate": "medium", "pitch": "medium", "volume": "loud" }
},
"characters": 27,
"total_cost": 0.00043
}
}
python
import base64
data = response.json()
audio = base64.b64decode(data["choices"][0]["message"]["audio"]["data"])
with open("speech.mp3", "wb") as f:
f.write(audio)

Images, speech and research

Speech to text

Transcribe audio with speaker labels using the speech-to-text model.

POST/v1/chat/completions

Send one audio file in the last user message, as an input_audio content part (WAV or MP3), a file part, or a data URL in attachments. Only the first file is transcribed.

language (or locale, which wins if both are sent) is the main locale, default en-US. The transcriber also detects en-US, es-ES, de-DE, fr-FR, it-IT, pt-BR, nl-NL, nb-NO, fi-FI and sv-SE.

json
{
"model": "speech-to-text",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "Transcribe this" },
{ "type": "input_audio", "input_audio": { "data": "<base64 audio>", "format": "mp3" } }
]
}
],
"language": "nb-NO"
}

Response

  • _bineric.phrases has one entry per phrase, with ISO 8601 startTime and duration.
  • Priced at $0.18 per hour of recognised speech.
  • Transcription runs as a batch job and does not stream. After 5 minutes it stops with 500 Transcription timed out after 5 minutes; split long recordings.
json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "Speech to Text",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Speaker 1: Hello and welcome.\nSpeaker 2: Thanks for having me."
},
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 },
"_bineric": {
"phrases": [
{ "speaker": 1, "text": "Hello and welcome.", "startTime": "PT0.5S", "duration": "PT1.8S" },
{ "speaker": 2, "text": "Thanks for having me.", "startTime": "PT2.4S", "duration": "PT1.6S" }
],
"total_cost": 0.0002
}
}

Images, speech and research

Deep research

Research a question on the web and get an answer with sources, using the deep-research model. $0.25 per call.

POST/v1/chat/completions
json
{
"model": "deep-research",
"messages": [
{ "role": "user", "content": "What changed in EU AI regulation this year?" }
],
"options": { "maxDepth": 5, "timeLimit": 180, "maxUrls": 5 }
}
OptionDefaultDescription
options.maxDepth5How many rounds of searching and reading.
options.timeLimit180Time limit in seconds.
options.maxUrls5Maximum number of pages to read.
streamfalseSend progress events while it works (top level or in options).

The research options are only read inside options. Each account can make 50 deep research calls a calendar month; unused calls do not carry over.

Response

Token counts in usage are estimates; you pay the fixed price per call.

json
{
"id": "chatcmpl-1768817914002-yq8xw50tv2g",
"object": "chat.completion",
"created": 1768817914,
"model": "Deep Research",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Based on my research..." },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 320, "completion_tokens": 540, "total_tokens": 860 },
"_bineric": {
"request_id": "req_abc123",
"citations": [
{ "url": "https://example.com/article", "title": "Article title", "description": "Relevant excerpt..." }
],
"activities": [
{ "type": "search", "status": "complete", "message": "Searching...", "timestamp": "2026-10-26T10:00:00Z", "depth": 1 }
],
"deep_research_info": { "usage_count": 5, "usage_limit": 50, "usage_left": 45 },
"total_cost": 0.25,
"response_time_ms": 12000
}
}

Streaming

With stream: true you get named events, not OpenAI chunks: info when research starts, activity for each step, and complete with the answer in response. There is no [DONE].

text
event: info
data: {"request_id":"req_abc123","model":"Deep Research","message":"Deep research started"}
event: activity
data: {"type":"search","message":"Searching...","request_id":"req_abc123"}
event: complete
data: {"success":true,"request_id":"req_abc123","model":"Deep Research","response":"Based on my research...","citations":[...],"activities":[...],"deep_research_info":{"usage_count":5,"usage_limit":50,"usage_left":45},"usage":{"prompt_tokens":320,"completion_tokens":540,"total_tokens":860,"total_cost":0.25,"response_time_ms":12000}}
event: error
data: {"success":false,"request_id":"req_abc123","error":{"type":"ProcessingError","message":"...","code":500}}

Errors

StatusMeaning
403 not_eligibleThis month's 50 calls are used up, or the balance is too low.
429Too many requests at once, or the research service's own limit.
500, 502The research failed.
503Deep research is temporarily unavailable.

When streaming, everything except the 403 arrives as an error event.

Files

Convert a file to base64

Upload a file and get it back as a data URL you can attach to a chat message.

POST/api/v1/media/base64

Multipart form data with one file in a field named file, up to 200 MB. Free; no credit is used.

curl -X POST https://api.bineric.com/api/v1/media/base64 \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@report.pdf"

Response

json
{
"success": true,
"request_id": "req_abc123",
"data": {
"base64String": "data:application/pdf;base64,JVBERi0xLjcK...",
"originalName": "report.pdf",
"fileInfo": { "mimeType": "application/pdf" },
"size": { "original": 102400, "base64": 136563 }
}
}

The MIME type is read from the file's bytes, so binary formats (images, audio, PDF, Office files) are recognised. Plain-text formats such as TXT, CSV, MD, JSON and HTML come back as application/octet-stream.

StatuscodeMeaning
400invalid_requestNo file, or larger than 200 MB.
401missing_api_key, invalid_api_keyNo key, or the key is wrong.
500internal_errorThe file could not be converted. A form field not named file also ends here.

Files

Decode base64

Send a base64 data URL and get the original file back.

POST/api/v1/decode-base64

The response is the file itself. Content-Type is detected from the decoded bytes, and Content-Disposition is inline; filename="file.<ext>". Errors: 400 invalid_request with param: "data" when data is missing, not a string or not valid base64, and 500 internal_error when decoding fails.

curl -X POST https://api.bineric.com/api/v1/decode-base64 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="}' \
--output pixel.png

Account

Usage

Your API usage and cost, per model.

GET/api/v1/monitoring/usage

Filter with startDate and endDate (YYYY-MM-DD). Send both: with only one, the result covers all time. Without dates, period is {"start": "all time", "end": "current"}.

model is the model's display name. recent_requests holds the last 5 paid requests. All numbers are JSON numbers.

bash
curl "https://api.bineric.com/api/v1/monitoring/usage?startDate=2026-10-01&endDate=2026-10-31" \
-H "Authorization: Bearer YOUR_API_KEY"
json
{
"success": true,
"data": {
"by_model": [
{
"model": "GPT-4o",
"usage": { "input_tokens": 50000, "output_tokens": 75000, "total_cost": 0.88, "request_count": 150 }
}
],
"total_usage": { "total_cost": 10.25, "total_tokens": 500000, "total_requests": 500 },
"recent_requests": [
{ "model": "GPT-4o", "cost": 0.0213, "tokens": 1840, "timestamp": "2026-10-31T14:30:00.000Z" }
],
"period": { "start": "2026-10-01", "end": "2026-10-31" }
}
}

Account

Daily usage

Today's usage and whether your credit is active.

GET/api/v1/monitoring/daily-usage
  • "Today" is the server's calendar day.
  • requests counts paid requests; the token and cost totals include every API request today.
  • last_request is null when there are no paid requests yet.
  • expires_at is only present while active is true.
bash
curl https://api.bineric.com/api/v1/monitoring/daily-usage \
-H "Authorization: Bearer YOUR_API_KEY"
json
{
"success": true,
"data": {
"payment_status": { "active": true, "expires_at": "2026-11-20T09:12:00.000Z" },
"today_usage": { "requests": 42, "input_tokens": 15000, "output_tokens": 22000, "total_cost": 0.85 },
"last_request": { "time": "2026-10-26T14:30:00.000Z", "model": "Claude Sonnet 4.6", "cost": 0.015 }
}
}

Account

Balance

Your credit balance and lifetime token usage.

GET/api/v1/monitoring/balance

balance is in USD. payment_status.active means a completed purchase in the last 30 days, and expires (present only while active) is 30 days after it. A new account has balance: 0 and lastUpdated: null.

bash
curl https://api.bineric.com/api/v1/monitoring/balance \
-H "Authorization: Bearer YOUR_API_KEY"
json
{
"success": true,
"data": {
"balance": 25.5,
"inputTokens": 500000,
"outputTokens": 750000,
"lastUpdated": "2026-10-26T14:30:00.000Z",
"payment_status": { "active": true, "expires": "2026-11-20T09:12:00.000Z" },
"usage": {
"daily": { "requests": 42, "tokens": { "input": 15000, "output": 22000 }, "cost": 0.85 },
"total": { "input_tokens": 500000, "output_tokens": 750000 }
}
}
}

Start building

Create a key, buy credits and make your first call in a few minutes.