onomeoonomeoBeta

Your tools. One API key.

Connect your favorite AI tools to onomeo. Free models are counted in calls; Claude, GPT and other big models are charged by usage.

OpenAI-compatible

Use these details in any OpenAI-compatible tool.

Base URL
https://onomeo.com/v1
API key
Model

Integrations

Don’t see your tool? Any OpenAI-compatible app can connect.Read the docs

When it does not connect

Some tools want the base URL with /v1 on the end, some add it themselves.

401, invalid key
The key was copied with a space on the end, or that key was from a browser whose site data has since been cleared.
404, not found
The base URL has /v1 twice, or none at all. Try it the other way.
400, model not allowed
The tool sent its default model name. Paste the Model value from above in its place.
402, insufficient balance
The balance is too low; this only happens on paid models, such as Claude and GPT. The message and the ways field say what would cover it: a free model, which is not charged, or what a fresh conversation would need. To add to the balance, top up on the Pricing page.
403 or 429, free-model call limit
With account_quota, network_quota (403) or site_busy (429; 403 when this message alone exceeds the site-wide limit), the free-model calls for this window are used up, or fewer are left than this message needs. Coding tools send the whole conversation and their files every time, and a longer message counts as several calls; see Billing and limits in the docs for how length is counted. Retry after the wait the response gives, or switch to a paid big model. With too_fast, too many requests came in one minute, whatever the model; wait a moment and retry.
An empty reply
Some tools set a very low output cap. Raise it, or leave that setting blank.

API documentation

Integrate onomeo's powerful AI models into your application with a simple and unified API. Build something great.

Quick start

Make your first API request in minutes. You'll need an API key and can use any HTTP client or OpenAI-compatible SDK.

POST/v1/chat/completions

Creates a chat completion response from one of onomeo's models.

Runnable versions of everything on this page, one file each in Python, Node and curl, are on GitHub.

Authentication

Use your API key in the Authorization header. Keep your key secure and never share it in client-side code.

Authorization: Bearer YOUR_API_KEY

Your balance lives on your account, so a lost key is recoverable — sign in again and create a new one on the My account page. Still, treat the key itself as a secret: do not commit it, do not share it. A key seen in use from several places at once gets disabled.

Leaked keys

When one of your keys appears in a public GitHub repository, GitHub notifies us within seconds and the key is disabled straight away. An email then goes to the address on your account, naming the key and where it was found.

A disabled key stops working immediately: any request still carrying it is answered with 401 unauthorized. Your account, your balance and your other keys are unaffected.

What to do next

  1. Create a replacement key in the console and put it into your application.
  2. Remove the old key from your code. Deleting the line is not enough: the key remains in the repository history, so rewrite the history, or treat that key as permanently public.
  3. Keep keys out of source code altogether. Read them from an environment variable or a secrets manager, and list the file holding them in .gitignore.

If you notice a leak yourself

Disable the key yourself in the console — it takes effect at once — then create a replacement. If you suspect someone else has used it, contact us and we will go through that key's request history with you.

Chat completions

Send a list of messages to a model and receive a generated response. This is the core endpoint for conversational AI. Request and response bodies follow the OpenAI shape.

Response

Reply
{
  "model": "MODEL_ID",
  "choices": [{
    "message": { "role": "assistant",
                 "content": "..." }
  }],
  "usage": { "total_tokens": 150 }
}

The number under usage is what this call used. On Claude, GPT and other big models the charge to your balance is worked out from it; on free models nothing is charged, and calls are counted by the length of what you send (see Billing and limits for how). It counts visible text only: what you sent plus what the model replied. Reasoning the model does before answering is not charged. On the big models, prompt_tokens and completion_tokens are the plain counts and total_tokens is the amount actually charged: returned text at the model's multiplier, sent text at a share of that, and the part of the sent text the provider billed as cached at a smaller share again (the shares are under Billing and limits).

Answers returned through the API to accounts without a balance end with the line "— via onomeo.com". Accounts with a balance do not get it. Tool-call answers, structured-output answers and answers that consist of a single JSON object or array are never changed. The line is not counted in usage, and calls made on your own provider key are returned as they are.

Parameters

The following parameters are commonly used with /v1/chat/completions.

ParameterTypeDescription
modelstringThe exact model ID from the current Models page.
messagesarrayA list of message objects with role and content.
temperaturenumberControls randomness. Use 0.0 for deterministic output.
max_tokensintegerOptional. Very small values are raised to a floor, so the answer does not come back empty.
streambooleanWhether to stream the response (default: false).
import requests

response = requests.post(
    "/v1/chat/completions",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    json={"model": "MODEL_ID", "messages": [
        {"role": "user", "content": "Hello!"}
    ]}
)
print(response.json())

Streaming

Set stream to true and you get server-sent events, same format as the OpenAI API. Every official client handles this out of the box.

Streamed request, Python
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY", base_url="/v1")
stream = client.chat.completions.create(
    model="MODEL_ID",
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

Billing works the same way on a stream: the final chunk carries the usage count, computed from the text you sent and the text you received; on big models the charge is worked out from it, and free models are not charged.

Images

Models that read images take pictures inside a user message: put the text and each image as parts of content, each image as a base64 data URL.

Request with an image
{
  "model": "MODEL_ID",
  "messages": [{
    "role": "user",
    "content": [
      { "type": "text", "text": "What is in this picture?" },
      { "type": "image_url",
        "image_url": { "url": "data:image/jpeg;base64,/9j/4AAQ..." } }
    ]
  }]
}

Models that read images right now: Loading the list…

On big models each image costs a fixed amount on every request that carries it, on top of the text; free models charge nothing for images. A request may carry at most 8 images; each must be PNG, JPEG, WebP or GIF and at most 3 MB. An image sent to a model that cannot read it is refused with model_no_vision, and nothing is charged. Images are passed to the model provider for the answer and are not stored on this site.

Other endpoints

The same key works on the endpoints below, so a tool built for another provider's request format can be pointed at this site as well. Each is called with POST, and the key goes in the Authorization header as Bearer unless a row says otherwise.

EndpointWhat it does
/v1/messagesAnthropic format, for Claude Code and other tools that use only that format. The key may also go in the x-api-key header. It takes this site's paid models (for accounts that have topped up) and models on your own keys, not the free models.
/v1/responsesOpenAI Responses format, used by Codex. It takes the same models as chat completions.
/v1beta/models/{model}:generateContentGoogle Gemini format, for Gemini CLI and other tools that use only that format: generateContent, streamGenerateContent (add alt=sse for server-sent events) and countTokens, with the model name in the path; GET /v1beta/models lists the models. The key may also go in the x-goog-api-key header or the key query parameter.
/v1/completionsThe older text completion format. The prompt is passed to the model as one user message and the answer comes back as text. One prompt per request; echo and logprobs are not supported.
/v1/embeddingsTurns text into vectors for search and knowledge bases. Models: loading. Up to 2,048 inputs per request; only gemini-embedding-001 accepts dimensions; encoding_format may be float or base64.
/v1/rerankOrders documents by how well they match a query, with the request fields used by Jina and Cohere: model, query, documents, top_n and return_documents. Models: loading.
/v1/audio/transcriptionsTurns speech into text. Send the audio as a multipart form field named file, at most 25 MB; response_format may be json, text or verbose_json. Models: loading.
/v1/images/generationsDraws pictures. Free models: loading; their pictures count toward the daily picture limit. n is the number of pictures, size is one of the sizes the model draws (such as 1024x1024), and response_format may be url or b64_json. The pictures are saved in your library, under Mine on the Works page.
/v1/videosMakes a short video with sound from one sentence, charged to the balance by the second. See Videos below.

Videos

POST /v1/videos makes a short video with sound from one sentence. The request body is JSON with these fields:

FieldDescription
modelA video model from the table at the end of this section.
promptOne sentence describing the video.
secondsThe length in seconds, one of those the model offers.
sizeOptional. Width by height, such as "1280x720" for landscape or "720x1280" for portrait.
resolutionOptional, in place of size: one of the model's resolutions, such as "480p" or "720p".
aspect_ratioOptional, with resolution: "16:9" or "9:16".
first_frameOptional, on models that take it: the picture the video starts on, as a data:image/…;base64 string.
last_frameOptional, on models that take it, and only with first_frame: the picture the video ends on, in the same form.
reference_imagesOptional, on models that take them: an array of pictures whose people, objects and style the video follows, in the same form. Not together with first_frame or last_frame.
Start a video
curl "/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "MODEL_ID",
    "prompt": "A lighthouse on a cliff at dusk, waves breaking below",
    "seconds": 5,
    "size": "1280x720"
  }'

The reply comes at once. It carries the video's id, status in_progress and progress 0:

Reply
{
  "id": "video_abc123",
  "object": "video",
  "model": "MODEL_ID",
  "status": "in_progress",
  "progress": 0,
  "created_at": 1760500000,
  "seconds": 5,
  "size": "1280x720"
}

Ask GET /v1/videos/{id} until status is completed, when the reply also carries url and completed_at, or failed, when it carries error with code and message. A video usually takes one to two minutes. GET /v1/videos/{id}/content downloads the MP4 file.

Check on the video, then download it
curl "/v1/videos/video_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"

curl -L "/v1/videos/video_abc123/content" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -o video.mp4

A video is charged to the balance by the second, at the price of its resolution, only once it has been made; a video that fails is not charged. The models and their prices right now:

ModelLengthsPrice per secondPictures it takes
Loading the list…

Models

These are the models you can call right now. Free models are not charged and are limited by number of calls. For the others the cost column is measured, not promised: a 30-day average of what one answer cost, in dollars, so a long answer costs more and a short one less.

Models are served through independent third-party providers but use the same request shape, so switching models only changes one string in your code. The list can change without notice: read it from the models endpoint at runtime rather than hard-coding names.

ModelRough cost per reply
Loading the list…

The same list, with who made each model, is on the Models page. To list them from code, call the models endpoint with your key:

List the models
curl "/v1/models" \
  -H "Authorization: Bearer YOUR_API_KEY"

Billing and limits

The balance is counted in US dollars and comes only from top-ups: the amount you pay is your balance, and it never expires. Claude, GPT and other big models are charged to it by usage, worked out from the visible text sent and received; the DeepSeek coding line is charged at what DeepSeek billed for the call. Free models are not charged; they are limited by number of calls, and a longer message counts as several calls. Length is counted over everything the request sends, the earlier conversation, the persona and file text included: each Chinese character counts 1 and every 4 other characters (letters, digits, spaces, punctuation) count 1, and each 50,000 counted, or part of it, is one call. The first time a single API request to a charged model would cost a large amount, the site does not run it: it answers with an ordinary reply stating the estimated cost, and nothing is charged. Sending the same request again runs it as usual. Requests of that size are not announced again; the notice comes once more only when a single request would cost ten times as much.

Each model's price is on the Pricing page, where you can also top up.

LimitValue
Loading the limits…

Check your balance any time from the My account page, or from code. The reply gives balance in the site's internal unit; divide it by money.unitsPerUsd from GET /api/info to get dollars:

Balance
curl "/api/me" \
  -H "Authorization: Bearer YOUR_API_KEY"

Errors

Every failure comes back as JSON with a stable code field. Match on the code, not on the message text, which is written for humans and may change. Amounts in an error body are in the site's internal unit; where a body carries need or balance, it also carries needUsd or balanceUsd, the same amount in dollars. When sending the same request again would fail the same way (a bad key, an insufficient balance, a used-up quota), the response also carries the x-should-retry: false header; only 408, 409, 429 and 5xx are worth retrying. Tools that resend every refusal (Codex, omp, or any streaming request sent again unchanged within seconds of a refusal) receive the refusal as an ordinary reply that states the reason, so that they stop.

Error body
{
  "error": {
    "code": "not_enough_credit",
    "balance": 6000,
    "balanceUsd": 0.01,
    "need": 15000,
    "needUsd": 0.025,
    "message": "Insufficient balance: this request needs about $0.025 and your balance is $0.01. Top up, or switch to a free model."
  }
}
CodeHTTP statusWhat it means
bad_key401The key is invalid, or no longer exists.
not_enough_credit402Balance too low for this request; it only happens on paid models, such as Claude and GPT. The body carries balance and need (what the request needs), with balanceUsd and needUsd beside them in dollars, and, when a way out can be worked out, ways: that free models are not charged (freeOk; it describes the billing and does not mean free-model calls are left right now), and what a new conversation with only the last message would need (freshNeed).
premium_daily_cap402This account has reached its daily limit on Claude, GPT and other big models; nothing is deducted. The body carries spent (used today), cap, need (this request's estimate) and buyer (whether the account has topped up).
coding_buyers_only402The DeepSeek coding line is open to accounts that have topped up. Nothing is deducted. The body carries buyUrl, where to top up.
premium_buyers_only402Claude, GPT and other big models are open to accounts that have topped up. Nothing is deducted. The body carries buyUrl, where to top up. The free trial in the web chat does not extend to API calls.
key_expired401This key is past its expiry date. Extend it on the My account page or use another key.
key_limit_reached402This key has reached its own spending cap; the account balance is untouched. The body carries the cap, the amount used and this request's estimate.
model_not_allowed400That model is not on the list. The body carries the allowed names.
model_paused400That model is switched off for now and returns to the list once it is back on. The body carries the names available right now. The big models the site pays for are switched off together when the balance the site keeps with their provider runs out; the body then also carries held: true.
model_no_vision400The request carries images and the model cannot read them. Pick a model that reads images, or leave the images out.
too_many_images400The request carries more images than allowed (8).
bad_image400An image is not a PNG, JPEG, WebP or GIF data URL of at most 3 MB.
request_too_large413The request body is larger than 8 MB.
ip_limit429Too many new accounts created from this network today. Returned at sign-in.
too_fast429Too many requests from this account within a minute. The body carries retryAfter in seconds; the Retry-After header carries the same value.
account_quota403This account has used its free-model calls for the current window, or has fewer left than this message needs (a longer message counts as several calls; see Billing and limits for how length is counted). Every key on the account shares the limit; Claude, GPT and other big models do not count toward it. The body carries retryAfter (seconds to wait; the Retry-After header carries the same value) and max (the window's limit); when the message needs more than one call, it also carries need (the calls this message counts as) and left (the calls left in this window). If need is above max, waiting does not help: the error message says the message is too long, and the conversation should be shortened or a new one started. While top-ups are open, an account that has not topped up also gets codingModels (the model names of the DeepSeek coding line, which is charged to the balance and not counted toward this limit) and buyUrl (where to top up).
network_quota403This network address has used its free-model calls for the current window, or has fewer left than this message needs; Claude, GPT and other big models do not count toward it. The body carries retryAfter (seconds to wait; the Retry-After header carries the same value) and max (the window's limit); when the message needs more than one call, it also carries need (the calls this message counts as) and left (the calls left in this window). If need is above max, waiting does not help: the error message says the message is too long, and the conversation should be shortened or a new one started. While top-ups are open, an account that has not topped up also gets codingModels (the model names of the DeepSeek coding line, which is charged to the balance and not counted toward this limit) and buyUrl (where to top up).
site_busy429 / 403The free-model calls shared by the whole site are used up for the current window, or fewer are left than this message needs; Claude, GPT and other big models are not affected. The body carries retryAfter (seconds to wait; the Retry-After header carries the same value); the site-wide limit and the calls left are not disclosed. If the message is larger than the whole window allows, the status is 403 and waiting does not help: the error message says the message is too long, and the conversation should be shortened or a new one started. While top-ups are open, an account that has not topped up also gets codingModels (the model names of the DeepSeek coding line, which is charged to the balance and not counted toward this limit) and buyUrl (where to top up).
premium_busy429Other answers on Claude, GPT and the other big models are still running and this request did not fit in, even after waiting about 10 seconds. The day's budget is not used up. Nothing is deducted. The body carries retryAfter in seconds; the Retry-After header carries the same value.
upstream_failed503The model provider did not answer. Nothing is deducted when this happens.
think_overrun503The model spent its whole output limit thinking and wrote no answer. For free models whose thinking can be turned off, the site first asks once more with thinking off; this error comes back only when that did not answer either. Nothing is deducted and the call is given back. Raise max_tokens, split the task into smaller parts, or pick another model. In a streamed request this error arrives before [DONE].
content_filtered400The model provider's content filter blocked this request, so there is no answer. Nothing is deducted and the call is given back. Rephrase the request, or pick another model. In a streamed request this error arrives before [DONE].
content_blocked422The last user message does not comply with the site's content policy (onomeo.com/content-policy), so it was not sent to any model. Nothing is deducted and no call is counted.
upstream_unconfigured503The service is not wired to a provider right now.
premium_budget_exhausted403The site-wide budget for Claude, GPT and other big models opens in four rounds a day (00:00, 06:00, 12:00 and 18:00 UTC), whatever a round leaves carrying over to the next. Returned while the current round is used up, until the next opens; once the whole day's budget is used up, until 00:00 UTC. The body carries resetAt (the reset time, ISO 8601) and retryAfter (seconds until then); the Retry-After header carries the same value. Nothing is deducted, and the free models still answer. The rounds do not apply to accounts that have topped up: they get this error only once the whole day's budget is used up. In the first three rounds, an account that has not topped up gets this error once 70% of the round is used up, and the body then also carries reserved: true and buyUrl, where to top up.
coding_line_out403The DeepSeek coding line is paused: the site's balance with DeepSeek is running low, or the day's spending limit for the line is reached. Nothing is deducted. It comes back once the site has added to its balance with DeepSeek, or the next day (UTC); pick another model meanwhile.
draw_daily_limit429Returned by the drawing page's own request (POST /api/draws), not by /v1. The account has used its free pictures for today, or fewer are left than this request asks for; nothing is drawn. The body carries today (used and max, in pictures) and resetsAt (the next 00:00 UTC, ISO 8601). Pictures drawn on your own provider key, and pictures on a model that is charged per picture, do not count.

FAQ

Can I use this in production?

No. This is a free beta with no uptime promise. Use it to try things, prototype, or run something that can fail without consequences.

What happens if I lose the key?

Nothing is lost. Sign in again and create a new key on the My account page: it is on the same account, with the same balance. Delete the old key from the My account page if you think someone else has it.

Can I create several keys?

Yes. Each account can hold up to 10 keys. They draw on the same balance and share the same call limits, so more keys do not mean more calls.

Do you keep my prompts?

For requests to the API, onomeo keeps an excerpt of each request and answer (the first 1,000 characters of the system prompt and the first 4,000 of the last user message and of the answer; the latest 100 per account, for at most 30 days), which the operator can read in the administration area; the amount used is also recorded, for billing and for counting calls. Conversations in the web chat are saved with your account (up to 50, and you can delete them). Either way, messages are forwarded to third-party model providers, and some of them, particularly on free tiers, may retain submitted content or use it to improve their services. onomeo does not use your content for training.

Is there image generation, video, audio or embeddings?

Yes. Pictures come through POST /v1/images/generations, and embeddings, rerank and speech-to-text through endpoints of their own (see Other endpoints); videos come through POST /v1/videos (see Videos). Text-to-speech is not offered, and function calling is not guaranteed on every model.

Why is my answer empty?

Almost always a max_tokens set too low. These models think before they answer, and the thinking counts against the same budget. Leaving the field out entirely is safest.