OpenAI-compatible API
Last updated 11 Nov 2026
What it is
The OpenAI-compatible API lets a tool that speaks OpenAI's chat completions format use ToRun's chat models, paid from your ToRun account. A coding agent such as opencode can use ToRun as its model provider, next to ToRun's MCP tools.
Address and sign-in
| Base URL | https://mcp.torun.ai/v1 |
| Sign-in | Authorization: Bearer <your developer key> |
Use the same developer key as for the MCP server: see Developer keys. A key created before the OpenAI-compatible API was added answers 403 insufficient_scope. A key's permissions never change, so create a new key.
The API has two endpoints, GET /v1/models and POST /v1/chat/completions. Any other path under /v1 answers 404 not_found.
Models
GET /v1/models lists torun/auto first, then every text model your plan can use, by its model id. Each model says:
- how much text it can read (
context_length) and how long a reply it can write (max_completion_tokens), - whether it can call tools (
supports_tools) and read images (supports_vision), - its price in Runs per million tokens (
pricing:inputandoutput).
torun/auto lets ToRun pick a model for each request: one that reads images when the request has an image, and one that calls tools when it sends tools.
Chat completions
POST /v1/chat/completions accepts:
messages, with the rolessystem,developer(treated assystem),user,assistantandtool,toolsandtool_choice(auto,none,requiredor one named function): your tool's own tools come back to it as tool calls, and ToRun never runs them,response_formatwithjson_object.json_schemais accepted and answered as JSON, but the schema itself is not enforced,temperature(0 to 2),top_p(0 to 1),max_completion_tokensormax_tokens,stop(up to 4 sequences),seedandreasoning_effort,streamandstream_options.include_usage.
n above 1, logprobs, top_logprobs, audio and any output other than text are refused with 400 unsupported_parameter rather than ignored.
Images
Send an image inline, as data:image/...;base64,... in an image_url part, up to 20 MB per request. An image sent as a link is refused with 400 image_url_not_supported: ToRun does not fetch it. Images are checked for safety, as in the app.
Streaming
With "stream": true the reply arrives as server-sent events in the chat.completion.chunk shape:
- The first chunk carries the role
assistant, and tool calls stream with theirindex. - While there is nothing to send, a
: keepalivecomment line arrives every 15 seconds; SSE parsers skip it. data: [DONE]ends a stream that succeeded.- With
stream_options.include_usage, the last chunk has an emptychoicesand carriesusage. - A failure after the stream started arrives as one
data: {"error": ...}event, with no[DONE].
A call without streaming is stopped after 110 seconds with 504 timeout. Send long requests with "stream": true.
Usage
usage carries prompt_tokens, completion_tokens, total_tokens, prompt_tokens_details.cached_tokens and completion_tokens_details.reasoning_tokens, plus torun_credits: what the call cost, in Runs.
Use it in opencode
The opencode configuration on the Developers page adds ToRun as a model provider next to the MCP server:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"torun": {
"npm": "@ai-sdk/openai-compatible",
"name": "ToRun",
"options": { "baseURL": "https://mcp.torun.ai/v1", "apiKey": "{env:TORUN_API_KEY}" },
"models": { "torun/auto": { "name": "ToRun Auto" } }
}
}
}
Any other tool that speaks the OpenAI chat API works the same way. The page's OpenAI API tab shows this call:
curl https://mcp.torun.ai/v1/chat/completions \
-H "Authorization: Bearer $TORUN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "torun/auto", "messages": [{"role": "user", "content": "Hello"}]}'
How calls are paid
API calls cost the same Runs as the same use in the app. Only paid funds pay for them: first your paid plan's allowance, then your wallet if you allowed that on the key. The free allowance never pays for API calls. The key's monthly and daily limits apply, and replies are checked for safety like chat replies.
Limits
Each key can make 60 requests a minute to this API and run 4 completions at the same time. Above that, the API answers 429 rate_limit_exceeded with a Retry-After header.
Errors
Every error has the shape {"error": {"message": ..., "type": ..., "param": ..., "code": ...}}. The message is in the language the request's Accept-Language header asks for.
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_json, missing_parameter, invalid_parameter, unsupported_parameter |
The request is malformed, or uses a parameter ToRun does not support. |
| 400 | image_url_not_supported |
An image was sent as a link; send it inline. |
| 400 | content_blocked |
The safety check blocked the content. |
| 400 | upstream_rejected |
The model's provider refused the request; the message says why. |
| 401 | invalid_api_key |
The key is missing, mistyped or revoked. |
| 402 | insufficient_credits, wallet_spend_not_allowed, spending_cap_reached |
The account or the key cannot pay for the call. |
| 403 | insufficient_scope |
The key was created before this API was added; create a new key. |
| 403 | model_not_available |
The model is not in your plan. |
| 403 | account_suspended, no_developer_access |
The account is suspended, or has no developer access. |
| 404 | model_not_found |
The model id is not one GET /v1/models lists. |
| 404 | not_found |
There is no such path under /v1. |
| 429 | rate_limit_exceeded |
Too many calls; wait for the time in Retry-After. |
| 500 | internal_error |
Something failed on ToRun's side. |
| 502 | upstream_error, empty_reply |
The model's provider failed, or sent an empty reply. |
| 503 | upstream_error, cap_unreadable, scan_unavailable |
A service the call needs is not available for a moment; try again. |
| 504 | timeout |
A call without streaming ran past 110 seconds. |
A request that cannot be paid answers 402, not 429, so a client does not keep retrying it.