/v1/chat/completionsUse this for chat, tools, JSON mode, and streaming with OpenAI SDKs.
Start with one copyable request, then follow the path that matches your job.
export INFERWAY_API_KEY="inferway_live_..." curl 'https://api.inferway.ai/v1/chat/completions' \ -H "Authorization: Bearer $INFERWAY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "inferway/qwen3.8-27b", "stream": true, "messages": [ { "role": "user", "content": "Say hello in one short sentence." } ] }'
curl 'https://api.inferway.ai/v1/chat/completions' \
-H "Authorization: Bearer $INFERWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "inferway/qwen3.8-27b",
"stream": true,
"messages": [
{
"role": "user",
"content": "Say hello in one short sentence."
}
]
}'Non-streaming requests pass through a CDN with roughly a 100-second first-byte timeout, so any long output must set stream=true. Non-streaming is fine for short completions. IDE and agent clients can choose non-streaming internally without exposing any setting: Inferway caps such requests at 4,096 total candidate output tokens and reports the applied per-candidate cap in the X-Inferway-Max-Tokens-Applied and X-Inferway-Max-Tokens-Reason response headers; longer output should still use streaming wherever the client supports it.
https://api.inferway.ai/v1$INFERWAY_API_KEYinferway/qwen3.8-27bdata: {
"id": "chatcmpl_...",
"object": "chat.completion.chunk",
"model": "inferway/qwen3.8-27b",
"choices": [
{
"index": 0,
"delta": { "role": "assistant", "content": "Hello" },
"finish_reason": null
}
]
}
data: [DONE]Most first-run issues are configuration issues. Check these before changing application code.
| Symptom | Likely cause | Fast fix |
|---|---|---|
| 401 | The key is missing, revoked, copied incorrectly, or not exported in this shell. | Re-copy the key from Console → API keys, then run echo $INFERWAY_API_KEY locally before retrying. |
| 404 | The client is pointed at the wrong base URL or duplicated the /v1 path. | Use https://api.inferway.ai/v1 as the base URL and call /chat/completions once. |
| 429 | The request reached an account or anonymous quota, or a per-request size bound. | Check the error dimension. Reduce input or max_tokens for a request-size limit; otherwise follow Retry-After when present. |
| 504 / timeout | A long non-streaming output hit the roughly 100-second CDN first-byte timeout. | Set stream=true on the request. |
# For OpenAI-compatible clients that read OpenAI env vars export OPENAI_API_KEY="$INFERWAY_API_KEY" export OPENAI_BASE_URL='https://api.inferway.ai/v1' export INFERWAY_MODEL='inferway/qwen3.8-27b'
The served model does not emit reasoning (thinking) tokens unless the request opts in.
Reasoning tokens are billed as output tokens at the output price and are visible in usage.completion_tokens_details.reasoning_tokens.
Enable thinking per request with chat_template_kwargs.enable_thinking=true (OpenAI SDKs: pass it via extra_body) or reasoning: {"enabled": true}.
The official OpenAI Python SDK works against any OpenAI-compatible base URL. Swap the base URL, keep your existing key. This non-streaming shape is fine for short completions; anything long must stream.
import os from openai import OpenAI client = OpenAI( base_url="https://api.inferway.ai/v1", api_key=os.environ["INFERWAY_API_KEY"], ) resp = client.chat.completions.create( model="inferway/qwen3.8-27b", messages=[{"role": "user", "content": "Say hello in one short sentence."}], max_tokens=64, ) print(resp.choices[0].message.content)
Choose a tool for setup and supported features. The configuration follows the model selected at the top of this page.
The first cURL request needs no dependencies. Install the OpenAI SDK only when you are ready to wire the integration into an application.
# Python pip install openai # TypeScript / Node.js npm install openai
Use Inferway as a custom provider in OpenCode. Your account must have model access enabled before connecting.
Context 262,144 Max output 131,072
Verified on 1.18.25, macOS 26.6.2 arm64, 2026-09-19: basic conversation and file-read tool round trip against inferway/qwen3.8-27b.
Save this as opencode.json at the root of the scratch folder. The provider section keeps the public model ID as the model key; the composite model selector is provider/model. {env:INFERWAY_API_KEY} interpolates the variable set earlier; the key itself never enters the file. The 1024 output limit is the tested validation preset; a larger limit was not verified here.
Set INFERWAY_API_KEY in the terminal used to launch the client. Keep the key out of the configuration file.
{
"$schema": "https://opencode.ai/config.json",
"model": "inferway/inferway/qwen3.8-27b",
"provider": {
"inferway": {
"npm": "@ai-sdk/openai-compatible",
"name": "Inferway",
"options": {
"baseURL": "https://api.inferway.ai/v1",
"apiKey": "{env:INFERWAY_API_KEY}"
},
"models": {
"inferway/qwen3.8-27b": {
"name": "Inferway",
"limit": {
"context": 262144,
"output": 1024
}
}
}
}
}
}opencode run --pure --format json --title 'Inferway basic check' --model 'inferway/inferway/qwen3.8-27b' --agent build --dir . 'Reply with exactly: connected'
opencode run --pure --format json --title 'Inferway read fixture' --model 'inferway/inferway/qwen3.8-27b' --agent build --dir . 'Read the file read-tool-fixture.txt and reply with exactly the nonce it contains, nothing else.'
Install the named client using its official instructions. Pi here means the pi-mono coding agent; Hermes means Nous Research's Hermes Agent.
Once your Inferway account is activated, get an API key from Console → API keys. Use a dedicated key for this client and review its model access and spending limits. Both live and test prefixes use the same inference and billing path; test is an environment label, not a free or simulated inference mode.
Use an Inferway key for Inferway's endpoint. An OpenRouter key belongs to OpenRouter and cannot authenticate to this address.
Keep the key in the client's credential store or your local environment. Do not paste it into a prompt, screenshot, or committed configuration. These examples use bash/zsh on macOS or Linux.
The prompt below hides your input and keeps the key out of shell history. Start the client from this same terminal; a separately opened app may not inherit this variable.
printf 'Inferway API key: ' IFS= read -r -s INFERWAY_API_KEY printf '\n' export INFERWAY_API_KEY
Use the full model ID inferway/qwen3.8-27b. The Base URL ends in /v1 once; do not append /chat/completions to a Base URL setting. Check that the response below contains the model ID.
curl --fail-with-body --silent --show-error --max-time 30 \ 'https://api.inferway.ai/v1/models' \ -H "Authorization: Bearer $INFERWAY_API_KEY"
OpenCode can load a project config from the project root (per-project config and custom paths are covered in the OpenCode configuration docs). Work in a scratch folder so the test never touches your daily settings or your global provider list.
The accepted live test used OpenCode CLI on macOS 26.6.2 arm64 against the catalog model below; check your own installed version before following along. git init just gives OpenCode a clean project root; no commit is needed for the check.
# Scratch folder with a small read fixture mkdir inferway-opencode-verify && cd inferway-opencode-verify && git init -q printf 'nonce-7f3a9c\n' > read-tool-fixture.txt
After the checks pass, copy the provider block (and the model entry under it) into your existing OpenCode config, keeping your own settings. You do not need the scratch folder or the test fixture for daily use.
Actual consumption is recorded by Inferway: open Console → Requests to see each request's status and token usage, and Console → Usage for totals. Numbers a client shows locally are its own estimates, not billing amounts; rely on the Console.
Authentication: check that an API key is present, active, and allowed to use the model. Reopen the client from the terminal containing the variable. Never print the full key when debugging.
Wrong endpoint or model: check for a duplicate /v1, use the exact published model ID, and confirm the client is using Chat Completions. A request to /responses or /completions cannot be repaired by changing the key.
Limits or timeout: check wallet balance and key limits, respect Retry-After, and reduce the prompt or output budget. Keep streaming enabled for long outputs. Avoid repeated agent retries while diagnosing.
When contacting support, share the client version, model ID, timestamp, and request ID if available. Redact credentials and source code.
To disconnect: revoke this tool's key in the Console and remove the Inferway provider from the client.
Standalone guideThe MCP endpoint is live. Point an MCP-capable client at the server URL below and authenticate with the same API key; tools are served over the standard protocol, and the same zero-retention rules apply.
Accounts with no spendable balance are routed to the free lane automatically instead of getting a 402 error — the same free tier as the REST API (60 requests/minute). Registered users are never treated worse than anonymous guests.
{
"mcpServers": {
"inferway": {
"url": "https://api.inferway.ai/v1/mcp/sse",
"headers": {
"Authorization": "Bearer $INFERWAY_API_KEY"
}
}
}
}Before you put traffic behind Inferway, start with the hub, then drill into live status and raw reports.
Inferway keeps the OpenAI-compatible path small and predictable, then exposes account, billing, usage, and agent operations as separate first-party endpoints.
/v1/chat/completionsUse this for chat, tools, JSON mode, and streaming with OpenAI SDKs.
/v1/interactionsUse this for video generation: durable background jobs you submit once and poll until the result is ready.
/v1/keys · /v1/billing · /v1/usage · /v1/requestsUse this for server-side key, wallet, usage, and request-metadata workflows.
| Endpoint | Method | Purpose |
|---|---|---|
| /v1/chat/completions | POST | OpenAI-compatible chat completions |
| /v1/interactions | POST | Asynchronous video generation jobs (four operations on one route) |
| /v1/models | GET | List published models with capability and pricing metadata |
| /v1/mcp/sse · /v1/mcp/messages | GET · POST | MCP server endpoint (live) |
| /v1/keys | GET / POST / DELETE | Manage direct API keys |
| /v1/billing | GET | Wallet summary and recent usage |
| /v1/billing/transactions | GET | Wallet ledger transactions |
| /v1/billing/checkout | POST | Create a Stripe Checkout top-up session |
| /v1/usage | GET | Aggregated usage for a time window |
| /v1/requests | GET | Request metadata history (no content) |
| /health | GET | Gateway and backend health status |
| /v1/stats | GET | Public status page payload |
Video generation does not return inline. Every call goes to POST /v1/interactions and names the operation in the body's op field; the job is durable, so a dropped connection never loses work already paid for.
| op | Purpose |
|---|---|
| prepare_upload | Request a short-lived, size-bounded upload contract for input media. |
| create | Submit a generation intent and receive an interaction id. Charged once, at the ordered duration. |
| get | Read the durable state, the current stage, and — once delivery commits — the result and its download URL. |
| cancel | Best-effort cancellation of a queued or in-flight job. |
Supported public endpoints are POST /v1/chat/completions, POST /v1/interactions and GET /v1/models. The legacy POST /v1/completions is not served: it answers 501 (not implemented) and names the chat completions route to use instead. POST /v1/messages (Anthropic-format) is served but not yet open to API keys: a configured client is refused with a permission error until we announce it.
Choose a model to see its published capability facts. API examples and tool setup use the same selection.
For pricing and regional availability, see Pricing.
Authorization: Bearer $INFERWAY_API_KEY
Inferway returns OpenAI-compatible error objects: {"error": { "type": "...", "message": "...", "code": "..." }}
Paid requests reserve prompt-estimate × input price + max_tokens × output price up front. Eligible requests can use registered FREE quotas when spendable funds are exhausted; FREE requests do not charge the wallet. A 402 refusal happens before dispatch and charges nothing. An authenticated request refused with 400 before it is dispatched appears in your Console request history with zero tokens and zero cost, so the failure can be diagnosed later. Balances render with 4 decimals; prices come from the live rate card.
Cached input tokens are reported in usage.prompt_tokens_details.cached_tokens and bill at the cache rate. On qwen3.8-27b the cache matches whole 1,600-token blocks and never reuses a prompt's last full block, so a request needs roughly 3,200 input tokens or more before any of it can hit; shorter requests always bill at the input rate.
The complete set of error codes /v1/chat/completions and /v1/agent/chat can return, read from the gateway's own catalog rather than transcribed. Each row carries the HTTP status, whether a retry is safe, and the exact message the API sends. Checkout, billing and key-management endpoints return their own codes, not listed here.
| Code | HTTP | Retry safe | Meaning |
|---|---|---|---|
| admission_paused | 503 | Yes — back off first | Paid admission is paused while we finish a service change. Retry shortly; nothing is wrong with this request. |
| authentication_error | 401 | No | Authentication failed. |
| conflict | 409 | No | A conflict occurred with the current state of the resource. |
| free_quota_exhausted | 429 | Yes — back off first | Free quota exhausted. Please retry later. |
| free_tier_unavailable | 503 | Yes — back off first | The free tier is temporarily unavailable; please retry shortly. |
| internal_error | 500 | No | An internal error occurred. |
| internal_tool_failure | 500 | No | An internal tool error occurred. |
| invalid_request | 400 | No | The request was invalid. |
| malformed_upstream | 502 | No | Received an invalid response from the upstream service. |
| model_unavailable | 503 | Yes — back off first | This model is temporarily out of service. Other models are unaffected; please retry later. |
| payment_required | 402 | No | Payment required. Add credit at https://inferway.ai/console/billing |
| rate_limited | 429 | Yes — back off first | Rate limit exceeded. Please retry later. |
| service_unavailable | 503 | No | Service outage in progress. Live status: https://inferway.ai/status |
| upstream_rejected | 422 | No | The upstream service rejected the request. |
| upstream_unavailable | 503 | Yes — back off first | The service is temporarily unavailable. |
Quota denials return HTTP 429. Check the error code, window and dimension, and follow Retry-After when present. Per-request size limits require reducing input or max_tokens; waiting does not change them.
| Subject | Limit | Window |
|---|---|---|
| Anonymous playground | 60 | per minute, per IP |
| Anonymous playground | 300 | per hour |
| Anonymous playground | 1,000 | per rolling 24 hours |
| Funded accounts | Account limits | Free caps no longer apply — visible in the console |
Registered free accounts: 8 requests/second burst, 60 requests/minute, 300 requests/hour and 1,000 requests/day, with 2 concurrent requests. No per-request input or output token cap, and no per-minute or daily token quota.
Hourly and daily request counts are rolling windows, not a reset at a fixed time. API keys on the same account share these request counts.
Each request is still bounded by the model's own context length and maximum output. Use streaming for outputs above 4,096 tokens.
The matrix below reflects how the gateway actually handles each parameter, based on real runtime verification.
| Parameter | Status | Notes |
|---|---|---|
| model | Supported | Rewritten to the backend model ID before proxying. |
| messages | Supported | Required non-empty list; validated and forwarded to the inference engine. |
| stream | Supported | Streaming path implemented; stream_options.include_usage is injected automatically. |
| temperature | Supported | Passed through to the inference engine; also logged for billing metadata. |
| top_p | Supported | Listed in supported_sampling_parameters and forwarded. |
| max_tokens | Supported | Passed through to the inference engine. |
| stop | Supported | Listed in supported_sampling_parameters and forwarded. |
| n | Untested | No gateway-level handling; forwarded unchanged. Behavior depends on the backend. |
| logprobs | Untested | No gateway-level handling; forwarded as part of the raw body. Not verified against live responses. |
| tools | Supported | Listed in supported_features: ["tools", "json_mode"] and forwarded. |
| response_format | Supported | Gateway advertises json_mode; the field is forwarded as part of the raw body. |
| vision input | Untested | Model metadata declares input_modalities: ["text"]. Gateway extracts image_url only for the CSAM hash check; inference behavior unverified. |
Thinking is off by default. To turn it on, send "reasoning": {"enabled": true} and budget at least ~16k max_tokens for that request — a smaller budget can be spent entirely on reasoning, leaving no visible answer.
Two minimal request shapes that each ship an inline image to a model whose catalog declares image_input. The image is inlined as a base64 data URL or base64 source; the gateway enforces the same per-image, per-kind total and request-level 16 MiB envelope as the playground.
Behavior of every snippet below is currently bounded by the same inference-unverified declaration listed in the compatibility matrix above.
image_url.content points at a data URL with the image bytes base64-encoded. The MIME matches what the catalog accepts.
POST https://api.inferway.ai/v1/chat/completions Authorization: Bearer $INFERWAY_API_KEY Content-Type: application/json { "model": "inferway/qwen3.8-27b", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "What is in this image?"}, { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" } } ] } ] }
Anthropic takes a base64 source object instead of a data URL; the gateway routes Anthropic-format requests to the same image_input envelope. The Messages endpoint is not yet open to API keys — see the endpoint reference above.
POST https://api.inferway.ai/v1/messages Authorization: Bearer $INFERWAY_API_KEY Content-Type: application/json { "model": "inferway/qwen3.8-27b", "max_tokens": 1024, "messages": [ { "role": "user", "content": [ {"type": "text", "text": "What is in this image?"}, { "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" } } ] } ] }
#!/usr/bin/env python3 """Minimal Inferway chat sample. Requires: pip install openai""" import os from openai import OpenAI client = OpenAI( base_url="https://api.inferway.ai/v1", api_key=os.environ["INFERWAY_API_KEY"], ) messages = [{"role": "system", "content": "You are a helpful assistant."}] while True: user = input("You: ") if not user: break messages.append({"role": "user", "content": user}) stream = client.chat.completions.create( model="inferway/qwen3.8-27b", messages=messages, stream=True, ) reply = "" print("Assistant: ", end="", flush=True) for chunk in stream: if not chunk.choices: continue piece = chunk.choices[0].delta.content if piece: reply += piece print(piece, end="", flush=True) print("\n") messages.append({"role": "assistant", "content": reply})