On this page

API reference

Every modality on its own OpenAI-compatible endpoint, behind one key.

Base URL
https://api.openllms.co/v1
Authentication
Authorization: Bearer PK-OPENLLMS-your-api-key
Schema
OpenAPI, for generating clients and Postman collections.

Your first request

Point an OpenAI client at the base URL above. It needs a key and a wallet with something in it.

Use your OpenAI client

pip install openai or npm i openai, then point its base URL here. Chat completions lists the fields it forwards; everything else is dropped.

An inference call needs a positive wallet balance — add funds — and the first call to an idle model can answer 503 while it starts. Wait for Retry-After, then retry.

How a request is served

Each model id maps to one or more backends. If the first cannot take the request the API falls through to the next, and the response still reports the id you asked for. On the audio, forecast and classify endpoints x-openllms-runtime names the kind of machine that served it; chat and embeddings do not carry it. Per-key request quotas are off unless one is set on your key, so the ceiling you normally meet is backend capacity — a 429 with code backend_saturated, where a key limit would be rate_limit_exceeded.

Headers on every request

AuthorizationBearer <key>Required

Your API key, from API keys in your dashboard. New keys start PK-OPENLLMS-; older PK-OPENLMS- and pk-llm- keys still work. Case-sensitive.

Content-Typeapplication/jsonRequiredOn POST

multipart/form-data on the audio upload endpoints — let your client set it.

Headers you get back

x-request-idstring

Support needs it to find your call. Send your own X-Request-Id (≤128 bytes) and it is echoed back; anything longer or blank is replaced with a generated one.

Retry-Afterseconds, ≥1On 429, most 503s, and 504

How long to wait before retrying.

x-openllms-cost-centsintegerSuccessful audio, forecast and classify responses

What the call cost, in whole cents. These calls have a 1¢ minimum, so 0 means the call was not charged.

x-openllms-runtimestringSuccessful audio, forecast and classify responses

Which runtime served it. turbo is a GPU, dedicated or serverless; tiny is a CPU Lambda; direct means no provider was reported. Any other value is the provider's own name.

from openai import OpenAI
client = OpenAI(
base_url="https://api.openllms.co/v1",
api_key="PK-OPENLLMS-your-api-key",
)
completion = client.chat.completions.create(
model="qwen-coder-3",
messages=[
{
"role": "user",
"content": "Say hello in one sentence.",
},
],
)
print(completion.choices[0].message.content)

Errors

One envelope: error.message, error.type, and error.code when there is one. Branch on status, then code. A request rejected by the transport layer — unparseable JSON, the wrong shape, an oversized body, a missing Content-Type — answers in plain text, not JSON.

Status codes you must handle

400a field failed validation, or the model's task_type does not match this endpoint

Field-validation errors carry no code, except on the audio upload endpoints. A task_type mismatch carries invalid_task_type.

Read error.message — it names the field, or the endpoint to use instead. Two 400s skip this envelope: unparseable JSON answers in plain text, and an error relayed from the model is passed through in the model's own shape. Parse defensively.

401the API key was missing, malformed, expired, revoked or blocked

code is invalid_api_key or api_key_blocked.

Use a live key.

402your wallet has no spendable balance

code is insufficient_balance. The check is balance above zero, never the price of the request.

Top up. Some models bill from wallet balance only, not promotional credit.

404no model with that id is active for API use, or no backend is configured to serve it

code is model_not_found. The two causes are indistinguishable.

Use an id from /v1/models whose status is live.

413the request body was larger than 32 MiB

Audio uploads have their own, lower limits — see Transcriptions.

Send a smaller body.

415a JSON endpoint was called without Content-Type: application/json

Audio format failures are listed under Transcriptions.

Set the header.

422the body is valid JSON but the wrong shape

Rejected before any handler runs, so the body is plain text.

Check the field types above.

429you were rate limited, or every backend for the model was busy

rate_limit_exceeded is a per-key limit; backend_saturated is capacity. Tell them apart by error.code.

Wait for Retry-After, then retry; both are transient.

500the request could not be completed

type is server_error; there is no code.

Retry. If it repeats, contact support and quote x-request-id.

502every backend for the model failed, or the model returned nothing

type is server_error. On a streamed request the 200 is already sent, so an empty result arrives as an empty stream rather than a 502.

Retry once. If it persists, try another id or contact support.

503usually the model is starting

type server_starting, code model_warming. Any other 503 is server_error, and its code names the reason.

For model_warming, wait for Retry-After and retry. For a server_error 503, back off and quote x-request-id.

504the model did not answer in time

code is backend_timeout. Audio, forecast and classify only; chat and embeddings surface a timeout as 502.

Retry — a 504 is not charged. Each attempt uses the serving backend's own deadline: 120 seconds by default, 300 where it has no runtime config, or whatever that backend is configured with.

Audio uploads and speech synthesis have failure modes of their own. Every error the API can return lists all of them with the cause and the fix.

The error envelope

HTTP/1.1 400 Bad Request
content-type: application/json
{
"error": {
"message": "Model 'lag-llama-forecaster' has task_type 'forecasting'. Use /v1/forecasts instead.",
"type": "invalid_task_type",
"code": "invalid_task_type"
}
}

The 402 envelope

HTTP/1.1 402 Payment Required
content-type: application/json
{
"error": {
"message": "Your wallet does not have enough credits to run this request. Add funds to continue.",
"type": "insufficient_quota",
"code": "insufficient_balance",
"recharge_url": "https://openllms.co/dashboard/wallet"
}
}

Chat completions

Generate a response from a text or vision model.

POST /v1/chat/completions

Example model

Body parameters

modelstringRequired

Model id, from /v1/models.

messages{ role, content }[]Required

The conversation, oldest first. role is system, user or assistant. content is a string — an array of parts is accepted only by a vision model, and returns 400 on a text one.

temperaturenumber, 0–2

Lower is more deterministic. Omit it and the backend serving the request supplies its own configured value if it has one; otherwise the model's default.

max_tokensinteger, 1–32,768

Maximum completion tokens. A backend may be configured with a lower ceiling, which caps a higher value silently and applies when you omit the field.

streamboolean

Server-sent events in OpenAI chunk format. delta carries role and content only.

top_pnumber

Nucleus sampling mass, 0 to 1. The model enforces the range, not the API. Omit it and the backend serving the request supplies its own configured value if it has one.

ninteger

How many completions to generate. Forwarded as sent; support varies by model.

stopstring | string[]*

Sequences that end the generation when produced. Forwarded as sent; the API does not check the shape.

userstring

An end-user identifier of your own.

* shape not checked by the API.

Billing — Billed per token, on prompt tokens plus completion tokens. The usage block is the model's own count, passed through unchanged; when the model reports zero prompt or completion tokens the API bills its own estimate instead, so the two can differ. The API strips the usage-only chunk from a stream, so read totals from a non-streamed call or from your usage page.

Request example

curl -sS https://api.openllms.co/v1/chat/completions \
-H 'Authorization: Bearer PK-OPENLLMS-your-api-key' \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-coder-3",
"messages": [
{
"role": "user",
"content": "Say hello in one sentence."
}
]
}'

Response example

{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1777560000,
"model": "qwen-coder-3",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Open LLMs is ready."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 14,
"completion_tokens": 6,
"total_tokens": 20
}
}

Transcriptions

Transcribe recorded speech.

POST /v1/audio/transcriptions

Models on this endpoint

  • Whisper Large v3

Multipart fields

modelstringRequired

Model id, from /v1/models. whisper-1 is an alias for whisper-large-v3.

filefile, ≤25 MiBRequired

wav, mp3, m4a, mp4, webm, ogg, oga, flac, mpeg, mpga or aac.

response_formatjson | verbose_json | text | srt | vtt

Default json. See Response formats.

languageISO-639-1

A hint, for example en. Send it when you already know the language.

timestamp_granularities[]("segment" | "word")[]

Accepted with or without the []. Timings reach you only through verbose_json, or as cues in srt and vtt.

temperaturenumber, 0–1

Lower is more deterministic.

promptstring

Free text that biases the spelling of names and jargon.

streamfalse

stream=true returns 400.

Response formats

jsonapplication/json

Default. A single object: { "text": "..." }.

verbose_jsonapplication/json

text plus segments of timed (start, end, text) cues. Treat segments as optional — a model that returns no timings gives an empty array, or omits it.

texttext/plain; charset=utf-8

The raw transcript as a plain-text body, with no JSON envelope.

srttext/plain; charset=utf-8

SubRip cues, numbered and timestamped.

vtttext/vtt; charset=utf-8

WebVTT subtitles for <track> captions, built from the same segments as srt. Always begins with a WEBVTT header, so a model that returns no timings gives a header and nothing else.

Billing — Priced per audio-minute, measured to the second and rounded up. Silence returns a 200 with an empty transcript and is charged for its length.

Error cases specific to audio

413the audio file is larger than 25 MiB (26,214,400 bytes)

code is audio_too_large.

Trim or re-encode to a shorter clip.

415the upload was not recognized as audio, by extension, Content-Type or leading bytes

code is unsupported_audio_format.

Use one of the extensions listed under file, or send an audio/* Content-Type.

400stream=true was sent

code is streaming_unsupported.

Omit it, or set it to false.

400a single-value part was sent twice

code is duplicate_<field>_field.

Send each part once; the last value does not win. timestamp_granularities[] is the exception.

400temperature is outside 0 to 1, or response_format is not one of the five

code is temperature_out_of_range or unsupported_response_format.

Send an allowed value, or omit the field.

400language is not an ISO-639-1 code

code is invalid_language.

Send a two-letter code such as en or es (yue, nan, wuu and cmn are also accepted), or omit the field.

413no backend serving this model accepts a file this size, even under 25 MiB

code is audio_too_large_for_runtime.

Send a smaller file.

503too many audio uploads are in flight

code is audio_capacity.

Wait for Retry-After, then retry.

Request example

curl -sS https://api.openllms.co/v1/audio/transcriptions \
-H 'Authorization: Bearer PK-OPENLLMS-your-api-key' \
-F "model=whisper-large-v3" \
-F "response_format=json"

Response example (json)

{
"text": "The quick brown fox jumps over the lazy dog."
}

Translations

Transcribe recorded speech into English, whatever language was spoken.

POST /v1/audio/translations

Models on this endpoint

  • Whisper Large v3

Models

List the models this API accepts. The same list for every key.

GET /v1/models

Fields on each entry (all always present)

idstring

The value to pass as model.

object"model"
createdunix seconds

When the model was added to the catalogue.

owned_bystring

Our provider namespace, open-llm on every catalogue model today. Not the publisher, and not who served the request.

task_typestring

Determines which endpoint serves the model. chat, vision, stt, tts, embedding, forecasting, classification and sentiment are the ones this reference covers; image and video map to endpoints that are not documented here yet, and anything else returns an empty endpoint.

input_modalitystring

What the model accepts, for example text or image+text.

output_modalitystring

What it returns, for example text, audio or labels.

endpointstring

The path that serves this model. Empty when no endpoint serves that task type yet.

statuslive | inactive

Filter on this. It reads live for every model whose deployment is running, which is normally every row here — but the list and this field are computed separately, so an inactive row can appear. A live model still answers 503 while a scaled-to-zero backend starts.

price_per_unitstring | null

Price for one billing_unit, in US dollars. null when the model is not priced that way.

billing_unitstring | null

What price_per_unit buys — audio_minute or character_million. null on a model priced per call.

Documented here

All 6. A model stays documented while its backend is off, so /v1/models can return fewer.

  • Qwen-Coder-3
  • Qwen-3.8-27B
  • Wan2.1-VACE Video
  • GLM-4.5-Air
  • Whisper Large v3
  • Qwen-2.5

Response example

{
"object": "list",
"data": [
{
"id": "qwen-coder-3",
"object": "model",
"created": 1777560000,
"owned_by": "open-llm",
"task_type": "chat",
"input_modality": "text",
"output_modality": "text",
"endpoint": "/v1/chat/completions",
"status": "live",
"price_per_unit": null,
"billing_unit": null
},
{
"id": "whisper-large-v3",
"object": "model",
"created": 1777560000,
"owned_by": "open-llm",
"task_type": "stt",
"input_modality": "audio",
"output_modality": "text",
"endpoint": "/v1/audio/transcriptions",
"status": "live",
"price_per_unit": null,
"billing_unit": null
}
]
}

Try it

Requests run here are live and billed to your wallet.

cURL

curl -sS https://api.openllms.co/v1/chat/completions \
-H 'Authorization: Bearer PK-OPENLLMS-your-api-key' \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-coder-3",
"messages": [
{
"role": "user",
"content": "Say hello from Open LLMs in one sentence."
}
],
"stream": false,
"temperature": 0.2,
"max_tokens": 64
}'