Inference APIs

Base URL and endpoints

https://api.inferenceapis.com/v1

/openai/v1 is accepted as well, so a Groq-style base URL works with only the host changed. The model field selects the model; each model also answers to the ids other providers use for it (see models and aliases).

EndpointPurposeAuth
POST /v1/chat/completionsChat and reasoning: streaming, tool calling, JSON outputKey
POST /v1/responsesThe same chat models through the OpenAI Responses API, for Codex CLI and newer SDK codeKey
POST /v1/messagesThe same chat models through the Anthropic Messages API, for Claude Code and Anthropic SDKsKey
POST /v1/embeddingsText to vectors for search and RAGKey
POST /v1/rerankScore passages against a queryKey
POST /v1/audio/speechText to speech, returns audio bytesKey
POST /v1/audio/transcriptionsSpeech to text, multipart uploadKey
GET /v1/voices?model=…Voices of a speech modelKey
GET /v1/modelsEvery accepted model id with its canonical idNone
GET /healthLiveness checkNone

Authentication

Send your key as a Bearer token. Create an account, add funds on the Billing page, then copy the key from the API Keys page.

Authorization: Bearer $INFERENCE_API_KEY
Treat the key like a password. Do not ship it in browser or mobile code or commit it to source control; call the API from your server and load the key from an environment variable or a secrets manager.

Quickstart

This example uses GPT-OSS 120B. Any chat model id from the catalog works in its place.

curl https://api.inferenceapis.com/v1/chat/completions \
  -H "Authorization: Bearer $INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-oss-120b",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Hello! What can you do?"}
    ]
  }'
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.inferenceapis.com/v1",
    api_key=os.environ["INFERENCE_API_KEY"],
)
response = client.chat.completions.create(
    model="openai/gpt-oss-120b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Hello! What can you do?"},
    ],
)
print(response.choices[0].message.content)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.inferenceapis.com/v1",
  apiKey: process.env.INFERENCE_API_KEY,
});
const response = await client.chat.completions.create({
  model: "openai/gpt-oss-120b",
  messages: [
    { role: "system", content: "You are a helpful assistant." },
    { role: "user", content: "Hello! What can you do?" },
  ],
});
console.log(response.choices[0].message.content);

Chat completions

POST /v1/chat/completions takes the OpenAI request body. These fields are passed through; others the model does not understand are ignored by it.

ParameterTypeNotes
model requiredstringCanonical id or an alias
messages requiredarrayRoles system, user, assistant, tool
max_tokensintegerCounts reasoning tokens too. Use a few hundred or more on reasoning models
temperature, top_pnumberSampling controls
streambooleanServer-sent events; usage arrives in the final chunk
tools, tool_choicearray, string|objectOpenAI function-calling format
response_formatobjectjson_object or json_schema
reasoning_effortstring"none" switches thinking off on any model; low, medium, high are passed to models that grade effort
stop, seedstring|array, integerStop sequences; seed for more reproducible sampling
200 OK · application/json (real response, reasoning shortened)
{
  "id": "p1fXe5T-z1gNr-a3c9ade91f80e802",
  "object": "chat.completion",
  "created": 1789664554,
  "model": "openai/gpt-oss-120b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello and welcome to you!",
        "tool_calls": [],
        "reasoning": "User asks: \"Say hello in five words.\" ..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 75,
    "completion_tokens": 125,
    "total_tokens": 200,
    "prompt_tokens_details": { "cached_tokens": 66 },
    "completion_tokens_details": { "reasoning_tokens": 110 }
  }
}

Reasoning models. GPT-OSS, DeepSeek and GLM think before they answer. The thinking is returned next to content, in reasoning on GPT-OSS and in reasoning_content on DeepSeek and GLM, and it is billed as completion tokens; usage.completion_tokens_details.reasoning_tokens says how many. If max_tokens is too small the budget is spent on thinking and content comes back empty. Llama 3.3 70B does not reason and has neither field.

Images. Qwen3-VL 235B accepts images in a message's content array, in the OpenAI format: {"type": "image_url", "image_url": {"url": "https://…"}} or a data:image/png;base64,… URI. Images bill as input tokens. The other chat models are text-only and will ignore or reject image parts.

Switching thinking off. Send reasoning_effort: "none" on any model. Each model family honours a different parameter for this and ignores the others, so the gateway translates; "minimal", reasoning: {"enabled": false} and thinking: {"type": "disabled"} are accepted too, and the X-Thinking: off response header confirms it. GPT-OSS cannot be switched off and goes to its lowest effort instead. Measured effect per model: model capabilities.

Streaming

Set "stream": true. Each event is a data: line with a chunk; text arrives in choices[0].delta.content and reasoning in delta.reasoning or delta.reasoning_content. The last chunk before [DONE] has an empty choices array and the usage object, so streamed requests can be metered without counting tokens yourself. You do not need to set stream_options.

Python · stream text and read usage from the last chunk
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.inferenceapis.com/v1", api_key=os.environ["INFERENCE_API_KEY"])

stream = client.chat.completions.create(
    model="zai-org/GLM-5.3-Flash",
    messages=[{"role": "user", "content": "Explain SSE in two sentences."}],
    max_tokens=600,
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:                      # final chunk: choices is empty, usage is set
        print("\n", chunk.usage.prompt_tokens, "in /", chunk.usage.completion_tokens, "out")
Wire format · last three events of a stream
data: {"id":"8757ca82","object":"chat.completion.chunk","model":"zai-org/GLM-5.3-Flash","choices":[{"index":0,"delta":{"content":null},"finish_reason":"stop"}]}

data: {"id":"8757ca82","object":"chat.completion.chunk","model":"zai-org/GLM-5.3-Flash","choices":[],"usage":{"prompt_tokens":15,"completion_tokens":129,"total_tokens":144,"completion_tokens_details":{"reasoning_tokens":123}}}

data: [DONE]

Tool calling

All five chat models returned a correct tool_calls entry for this request when we tested them on September 17, 2026. Arguments arrive as a JSON string. In a stream they arrive as delta.tool_calls fragments to concatenate.

Python · tool calling round trip
import json, os
from openai import OpenAI

client = OpenAI(base_url="https://api.inferenceapis.com/v1", api_key=os.environ["INFERENCE_API_KEY"])
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
    },
}]
messages = [{"role": "user", "content": "What is the weather in Paris?"}]

first = client.chat.completions.create(model="openai/gpt-oss-120b", messages=messages, tools=tools, max_tokens=800)
call = first.choices[0].message.tool_calls[0]          # name="get_weather", arguments='{"city": "Paris"}'
args = json.loads(call.function.arguments)

messages += [first.choices[0].message,
             {"role": "tool", "tool_call_id": call.id, "content": json.dumps({"city": args["city"], "temp_c": 18})}]
final = client.chat.completions.create(model="openai/gpt-oss-120b", messages=messages, tools=tools, max_tokens=800)
print(final.choices[0].message.content)

JSON and structured output

Both forms of response_format work on every chat model here. With json_schema the reply is constrained to your schema. Mention JSON in the prompt as well, and leave room in max_tokens for the reasoning that happens first.

Python · JSON mode and JSON-schema output
# JSON mode: any valid JSON object
resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash",
    messages=[{"role": "user", "content": "Return a JSON object with keys city and country for Paris."}],
    response_format={"type": "json_object"},
    max_tokens=800,
)

# Schema-constrained: the reply must match your schema
resp = client.chat.completions.create(
    model="deepseek-ai/DeepSeek-V4-Flash",
    messages=[{"role": "user", "content": "Give me a person named Ada, age 36."}],
    response_format={"type": "json_schema", "json_schema": {"name": "person", "schema": {
        "type": "object",
        "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
        "required": ["name", "age"], "additionalProperties": False}}},
    max_tokens=800,
)
print(resp.choices[0].message.content)     # {"name": "Ada", "age": 36}

Responses API

POST /v1/responses serves every chat model through OpenAI's newer Responses format, streaming included. It exists because some clients speak nothing else, Codex CLI among them. Requests are translated to chat completions on our side, so pricing and models are identical. It is stateless: send the whole conversation in input on every call, as Codex does. previous_response_id, store, background mode and OpenAI-hosted tools such as web search are not supported; function tools and Codex's freeform tools are. Two Codex-only request shapes are translated so that they work on every model: MCP servers and sub-agent tools, which Codex sends inside a namespace wrapper, are expanded and each call comes back with its namespace restored; Multi-Agent V2 agent_message hand-offs become user messages. Details and per-model test results: MCP tools in Codex on a custom provider.

Python · Responses API
resp = client.responses.create(
    model="deepseek-ai/DeepSeek-V4-Flash",
    instructions="You are a terse assistant.",
    input="Name three uses of a reranker.",
    max_output_tokens=800,
    reasoning={"effort": "low"},
)
print(resp.output_text)
print(resp.usage.input_tokens, resp.usage.output_tokens)
Codex CLI · ~/.codex/config.toml
model = "zai-org/GLM-5.3"
model_provider = "inferenceapis"

[model_providers.inferenceapis]
name = "Inference APIs"
base_url = "https://api.inferenceapis.com/v1"
env_key = "INFERENCE_API_KEY"
wire_api = "responses"

We ran a real Codex CLI task, write a script, run it, report the output, through this route on every large model here. Setup details: Codex CLI.

Messages API (Anthropic format)

POST /v1/messages serves every chat model through the Anthropic Messages format, streaming included, with x-api-key or a bearer token. It exists because Claude Code speaks nothing else. Requests are translated to chat completions on our side, so models and prices are the same as everywhere else here. System prompts, text and image blocks, tool_use and tool_result, tool_choice (auto, any, tool, none), stop_sequences and output_format are translated. thinking: {type: "enabled"} (or adaptive) leaves the model's reasoning on and streams it as thinking blocks; no thinking field switches it off, as in Anthropic's own semantics. Replayed thinking blocks are dropped on the way in; every model here accepts the history without them. Anthropic-hosted server tools (web search, computer use, text editor, code execution), mcp_servers, container and the Batches API are not supported; dropped fields are listed in the X-Tools-Dropped and X-Dropped-Params response headers. POST /v1/messages/count_tokens returns an estimate. Errors use Anthropic's envelope ({"type":"error","error":{"type":…,"message":…}}).

Python · Anthropic SDK
import os
from anthropic import Anthropic
client = Anthropic(base_url="https://api.inferenceapis.com", api_key=os.environ["INFERENCE_API_KEY"])
msg = client.messages.create(
    model="deepseek-ai/DeepSeek-V4.1-Flash",
    max_tokens=1024,
    thinking={"type": "enabled", "budget_tokens": 2048},   # omit to switch the model's reasoning off
    tools=[{"name": "read_file", "description": "Read a file.", "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}}],
    messages=[{"role": "user", "content": "What is in /app/config.json?"}],
)
print(msg.stop_reason, [b.type for b in msg.content])   # tool_use ['thinking', 'tool_use']
Shell · Claude Code
export ANTHROPIC_BASE_URL="https://api.inferenceapis.com"
export ANTHROPIC_AUTH_TOKEN="your-key"
export ANTHROPIC_MODEL="zai-org/GLM-5.3"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="deepseek-ai/DeepSeek-V4.1-Flash"
claude

Claude Code 2.1.275 completed a real task (run the tests, fix two bugs, run them again) through this route on eight models, at 1 to 6 cents per run. Setup, per-model timings and the things to know: Claude Code.

Embeddings

POST /v1/embeddings follows the OpenAI request: model, input as a string or an array of up to 1,024 strings, optional dimensions and encoding_format. Billing is per input token. We do not meter requests per minute or per day; a load test sustained 2 to 4 million tokens per minute on BGE-M3, and the gateway retries by itself when the backend is briefly saturated (details). Vectors from different models are not comparable, so OpenAI's model ids are deliberately not aliased; choose BGE-M3 or Qwen3 Embedding 8B and re-embed once.

Python · embeddings
resp = client.embeddings.create(
    model="BAAI/bge-m3",
    input=["The cat sat on the mat.", "Le chat est sur le tapis."],
)
vectors = [d.embedding for d in resp.data]        # 2 vectors of 1,024 floats
print(resp.usage.total_tokens)

# Qwen3 Embedding lets you choose the vector length
short = client.embeddings.create(model="Qwen/Qwen3-Embedding-8B", input="hello", dimensions=512)

Rerank

POST /v1/rerank takes a query and up to 1,000 documents and returns a relevance score from 0 to 1 for each, best first. Use it after an embedding search: fetch 20 to 100 candidates, rerank, keep the top few for the prompt. Optional fields: top_n and return_documents. Billing is per token read by the model, reported in usage.total_tokens. Model: Qwen3 Reranker 8B.

cURL · rerank
curl https://api.inferenceapis.com/v1/rerank \
  -H "Authorization: Bearer $INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-Reranker-8B",
    "query": "What is the capital of France?",
    "documents": ["Bananas are yellow.", "Paris is the capital of France.", "Berlin is in Germany."],
    "top_n": 2
  }'
# {"object":"list","model":"Qwen/Qwen3-Reranker-8B",
#  "results":[{"index":1,"relevance_score":0.978},{"index":2,"relevance_score":0.00002}],
#  "usage":{"total_tokens":251}}

Text to speech

POST /v1/audio/speech returns audio bytes. The response is the complete file; chunked audio streaming is not supported yet.

ParameterTypeNotes
model requiredstringhexgrad/Kokoro-82M or canopylabs/orpheus-3b-0.1-ft; tts-1 is an alias of Kokoro
input requiredstringUp to 20,000 characters per request
voicestringDefaults to af_heart (Kokoro) or tara (Orpheus). The Kokoro voice prefix sets the language
response_formatstringmp3 (default), wav or raw PCM
speednumberPlayback speed multiplier, for example 1.1
languagestringOptional pronunciation hint, for example ja
cURL · text to speech
curl https://api.inferenceapis.com/v1/audio/speech \
  -H "Authorization: Bearer $INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "hexgrad/Kokoro-82M", "voice": "af_heart", "input": "Hello there, this is a test.", "response_format": "mp3"}' \
  --output hello.mp3 -D -
# HTTP/1.1 200 OK
# Content-Type: audio/mpeg
# X-Usage-Characters: 28

Billing is per Unicode character of input, reported in the X-Usage-Characters response header. Voices: GET /v1/voices?model=hexgrad/Kokoro-82M with your key, or the voices by language pages.

Speech to text

POST /v1/audio/transcriptions takes a multipart upload: mp3, mp4, m4a, wav, webm, ogg or flac, up to 100 MB. Billing is per minute of audio, measured from the file before it is transcribed.

FieldTypeNotes
model requiredstringopenai/whisper-large-v3 or nvidia/parakeet-tdt-0.6b-v3; whisper-1 is an alias of Whisper Large v3
file requiredfileThe audio
languagestringISO 639-1 code. Skips detection; matters on short clips and for languages detection confuses (see accuracy by language)
promptstringNames and jargon spelled the way you want them
response_formatstringjson (default), verbose_json, text, srt, vtt
timestamp_granularities[]arraysegment and/or word, with verbose_json
temperaturenumber0 to 1
diarizebooleanSpeaker labels (Whisper Large v3 only): every word gets a speaker, segments become speaker turns with a speaker field, plus speakers and the upstream speaker_segments. Forces verbose_json unless you ask for text, srt or vtt, which carry SPEAKER_00: labels. diarization and speaker_labels are accepted as aliases. Measured results
min_speakers, max_speakersintegerHints for the diarizer; with diarize only
cURL · transcription with word timestamps
curl https://api.inferenceapis.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $INFERENCE_API_KEY" \
  -F "model=openai/whisper-large-v3" \
  -F "file=@hello.mp3" \
  -F "language=en" \
  -F "response_format=verbose_json" \
  -F "timestamp_granularities[]=word"
200 OK · verbose_json (real response, shortened)
{
  "language": "en",
  "duration": 1.83,
  "text": "Hello there, this is a test.",
  "words": [
    { "word": "Hello",  "start": 0.06, "end": 0.26 },
    { "word": "there,", "start": 0.36, "end": 0.60 }
  ]
}

Models and aliases

GET /v1/models needs no key and lists every id the API accepts. Each entry carries canonical, the id it resolves to, and type, which decides the endpoint. An alias bills at the canonical model's rate.

GET /v1/models · two of the entries
{ "object": "list", "data": [
  { "id": "openai/gpt-oss-120b", "object": "model", "type": "chat", "canonical": "openai/gpt-oss-120b" },
  { "id": "gpt-oss-120b",        "object": "model", "type": "chat", "canonical": "openai/gpt-oss-120b" }
]}
ModelCanonical idAlso acceptedEndpoint
GPT-OSS 120B openai/gpt-oss-120b gpt-oss-120b chat/completions, responses
DeepSeek V4 Flash deepseek-ai/DeepSeek-V4-Flash deepseek-v4-flash, deepseek-ai/DeepSeek-V4-Flash-0731, deepseek-v3, deepseek-ai/DeepSeek-V3 chat/completions, responses
DeepSeek V4.1 Flash deepseek-ai/DeepSeek-V4.1-Flash deepseek-v4.1-flash, deepseek-flash chat/completions, responses
GLM 5.3 Flash zai-org/GLM-5.3-Flash glm-5.3-flash chat/completions, responses
Llama 3.3 70B Instruct meta-llama/Llama-3.3-70B-Instruct-Turbo llama-3.3-70b, llama-3.3-70b-instruct, llama-3.3-70b-versatile, llama-3.1-8b-instant chat/completions, responses
GLM 5.3 zai-org/GLM-5.3 glm-5.3 chat/completions, responses
DeepSeek V4 Pro deepseek-ai/DeepSeek-V4-Pro deepseek-v4-pro, deepseek-ai/DeepSeek-V4-Pro-0813 chat/completions, responses
MiniMax M3 MiniMaxAI/MiniMax-M3 minimax-m3 chat/completions, responses
Kimi K2.7 Code moonshotai/Kimi-K2.7-Code kimi-k2.7-code chat/completions, responses
GPT-OSS 20B openai/gpt-oss-20b gpt-oss-20b chat/completions, responses
Qwen3.8 Flash Qwen/Qwen3.8-Flash qwen3.8-flash chat/completions, responses
Qwen3-VL 235B Qwen/Qwen3-VL-235B-A22B-Instruct qwen3-vl, qwen3-vl-235b chat/completions, responses
Kokoro 82M hexgrad/Kokoro-82M kokoro, kokoro-82m, tts-1 audio/speech
Orpheus 3B canopylabs/orpheus-3b-0.1-ft orpheus, orpheus-3b audio/speech
Whisper Large v3 openai/whisper-large-v3 whisper-large-v3, whisper-large-v3-turbo, whisper-1, whisper audio/transcriptions
Parakeet TDT 0.6B v3 nvidia/parakeet-tdt-0.6b-v3 parakeet, parakeet-tdt-0.6b-v3 audio/transcriptions
Voxtral Small 24B mistralai/Voxtral-Small-24B-2507 voxtral, voxtral-small, voxtral-small-24b audio/transcriptions
Voxtral Mini 3B mistralai/Voxtral-Mini-3B-2507 voxtral-mini, voxtral-mini-3b audio/transcriptions
BGE-M3 BAAI/bge-m3 bge-m3 embeddings
Qwen3 Embedding 8B Qwen/Qwen3-Embedding-8B qwen3-embedding-8b embeddings
Qwen3 Reranker 8B Qwen/Qwen3-Reranker-8B qwen3-reranker-8b rerank

Errors

Errors use the OpenAI envelope, so SDK exception types map as usual (AuthenticationError, NotFoundError and so on). Check for error before reading choices.

Error body · same envelope as OpenAI
{
  "error": {
    "message": "Model 'nope' not found. See GET /v1/models.",
    "type": "invalid_request_error",
    "param": null,
    "code": "model_not_found"
  }
}
StatuscodeMeaningRetry?
400wrong_endpointThe model exists but belongs to another endpoint, for example a speech model sent to chatNo
400—Body is not valid JSON, or a required field is missingNo
401missing_api_key, invalid_api_keyNo Bearer token, or the key is not recognisedNo
402insufficient_balancePrepaid balance is zero. Add creditsAfter topping up
404model_not_foundThe id is not in GET /v1/modelsNo
413input_too_long, file_too_largeMore than 20,000 characters of speech input, or an upload over 100 MBNo, split the input
429upstream_rate_limitedRare: the inference backend is saturated for that model. We do not meter your requestsYes, honour Retry-After
502upstream_error, upstream_authThe inference backend failed; the message says howYes, with backoff
503model_unavailableThe model is listed but not being served right nowYes, or use another model

Your requests and tokens are not metered per minute or per day, so a 429 here never means you used up a quota; it means the backend is busy and a retry will work. Validation errors from the model itself, such as a prompt longer than the context window, come back as 400 with the backend's message. For the errors other providers return, see the provider error reference.

Limits

LimitValue
Requests or tokens per minute or per dayNot metered. Abusive traffic may be throttled
Context windowPer model, from 131K tokens (GPT-OSS 120B, Llama 3.3 70B) to 1M tokens (the DeepSeek V4 and GLM 5.3 models); each model page states its own
Embedding inputs1,024 texts per request; 8K tokens each on BGE-M3, 32K on Qwen3 Embedding
Rerank documents1,000 per request
Speech input20,000 characters per request
Audio upload100 MB per request
SpendYour prepaid balance; requests return 402 at zero

Billing and usage

Usage is paid from prepaid credits; top up on the Billing page. Each request is metered once it completes: chat on prompt plus completion tokens, speech on input characters, transcription on audio minutes, at the rates on the pricing page. Cached input is discounted. When the beginning of your prompt matches a recent request, the backend reuses its work and reports the count in usage.prompt_tokens_details.cached_tokens; those tokens bill at the model's cached-input rate, which is about 80 to 98 percent below its normal input rate. Nothing needs switching on. It matters most for agents and long chats that resend a growing conversation every turn: keep the start of the prompt identical between requests and most of each turn is cached. A request that fails with a 4xx is not charged. What is stored per request is the model id, the unit counts, the cost and the time; prompts, audio and outputs are not retained, by us or by the GPU providers: zero data retention applies end to end (details).

Spend controls: limits, alerts and cost per request

Every key can carry a spend limit (USD per day, week, calendar month, or lifetime), an expiry date, a list of allowed models, and can be paused. The account as a whole can carry its own daily, weekly or monthly limit, and you get an email at 80% and 100% of any limit and when the balance drops below a threshold you choose (default $1). All of it is set on the API Keys page or through the MCP server. Periods reset at 00:00 UTC; the week starts on Monday.

When a limit is hit the request is refused before it costs anything: 402 with code key_spend_limit_reached or account_spend_limit_reached, a Retry-After header counting down to the reset and an X-Spend-Limit-Resets-At header. A paused key returns 403 key_paused, an expired one 403 key_expired, and a model outside a key's list 403 model_not_allowed. Other keys on the account keep working when only one key's limit is reached.

Cost on every response. Non-streamed responses carry X-Cost-USD (this request) and X-Balance-Remaining headers, plus X-Key-Spend-Remaining and X-Account-Spend-Remaining when a limit is set. The JSON usage object gains a cost field in USD on chat completions (including the final chunk of a stream), Responses, Messages, embeddings and rerank.

GET /v1/usage returns the balance, spend today, this week, this month and over the last N days (?days=30), the account limit with its reset time, every key's limit, spend and status, and a by-model breakdown. It works even when the balance is zero or a limit is reached, so an agent that receives a 402 can read exactly why and when it clears.

curl -s https://api.inferenceapis.com/v1/usage -H "Authorization: Bearer $INFERENCE_API_KEY"

Not supported yet

Stored responses and OpenAI-hosted tools on the Responses API, image generation, the Batch and Files APIs, fine-tuning, real-time or streaming transcription and streamed audio output. If one of these blocks you, say so; requests decide what gets built next.