How to use ONEWAY.
One API for many models, with spend you can see and control. You're signed in as owner; parts your role can't open are marked.
On this page
Start in five minutes
From nothing to a metered request.
- Create a project for each product or service, on the Overview. Usage, keys and budgets are per project; the balance is shared.
- Add your provider keys under Provider keys (owners and admins). A model works once its provider has a key; providers bill you directly. ONEWAY-provided models are coming soon.
- Create an API key on the project page. Copy it straight away: only a hash is stored, so it is shown once. Use a
testkey in development and alivekey in production. - Point your client at ONEWAY: base URL
https://oneway-gateway.oneway-gateway.workers.dev/v1, your key as the Bearer token, and a model ID from Models. - Watch it land on Requests a few seconds later, with its cost, tokens and latency.
The dashboard, page by page
What each page is for and who sees it in the sidebar.
| PAGE | WHAT IT'S FOR | WHO SEES IT |
|---|---|---|
| Overview | This month's spend and requests, the model mix, every project and the latest requests. Create a project here. | Everyone but members |
| Projects | Open one from the sidebar picker. Each has its own API keys, monthly budget, usage and a copy-paste quickstart. | Everyone but members |
| Usage | Spend by day, project, model, and by the customer and feature headers you send. | Everyone but members |
| Requests | The last 100 requests. Open one for its retries, fallbacks, attribution and (if kept) prompt and response. | Everyone but members |
| My usage | Your personal keys, your spend and limit, and your own recent requests. | People in a department |
| Departments | Split the balance into team allocations, add people, set personal limits and make service keys. | Owners, admins, billing, leads |
| Leaderboard | Who uses AI most, by requests and streaks on personal keys. Never shows spend. | Everyone, when turned on |
| Models | Every model you can call, its ID, context window and price per million tokens. | Everyone |
| Billing | The prepaid balance, runway, top-ups by card or UPI, payments and credit history. | Owners, admins, billing |
| Provider keys | Your own OpenAI, Anthropic, Gemini or Bedrock keys, and other OpenAI-compatible providers. | Owners and admins |
| Members | Who is in the organisation and their role. Owners and admins invite people here. | Everyone but members |
| Audit log | Every security-relevant change: keys, members, budgets, credits. Can't be edited. | Owners and admins |
| Security | Two-factor authentication, passkeys and the devices signed in as you. | You (shield icon, top right) |
Calling the API
OpenAI- and Anthropic-compatible. Change the base URL and key; request bodies stay the same.
curl, on POST /v1/chat/completions (every model):
curl https://oneway-gateway.oneway-gateway.workers.dev/v1/chat/completions \
-H "Authorization: Bearer $ONEWAY_API_KEY" \
-H "content-type: application/json" \
-d '{"model": "anthropic/claude-sonnet-5-5",
"messages": [{"role": "user", "content": "Hello"}]}'OpenAI SDK, JavaScript:
import OpenAI from "openai";
const ai = new OpenAI({
baseURL: "https://oneway-gateway.oneway-gateway.workers.dev/v1",
apiKey: process.env.ONEWAY_API_KEY,
defaultHeaders: { "x-oneway-feature": "support-bot" },
});
const reply = await ai.chat.completions.create({
model: "anthropic/claude-sonnet-5-5",
messages: [{ role: "user", content: "Hello" }],
});OpenAI SDK, Python, streamed:
import os
from openai import OpenAI
ai = OpenAI(base_url="https://oneway-gateway.oneway-gateway.workers.dev/v1", api_key=os.environ["ONEWAY_API_KEY"])
stream = ai.chat.completions.create(
model="anthropic/claude-sonnet-5-5",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")Anthropic SDK, on POST /v1/messages (Claude models; the key works as x-api-key too):
import Anthropic from "@anthropic-ai/sdk";
const ai = new Anthropic({
baseURL: "https://oneway-gateway.oneway-gateway.workers.dev",
apiKey: process.env.ONEWAY_API_KEY,
});- Model IDs are
provider/model.GET /v1/modelslists the ones your key can call. POST /v1/responsespasses OpenAI's Responses API through for OpenAI models.- Streaming works on all three endpoints and is billed for its full usage.
- Other OpenAI-compatible providers, added under Provider keys, Other providers, are called as
custom/<name>/<model>on chat completions. - Keep keys on the server, in environment variables. Never ship one to a browser.
- More examples, and the same reference without signing in, are in the developer docs.
Request headers
Optional. Attribution headers make Usage show who and what the spend is for.
| HEADER | SENT ON | MEANING |
|---|---|---|
x-oneway-customer | Request | Your end customer's ID. Spend is broken down by it on Usage. |
x-oneway-feature | Request | Which feature made the call, e.g. support-bot. Also on Usage. |
x-oneway-agent | Request | Which agent or job made the call. |
x-oneway-release | Request | Your git commit or tag, for cost per deploy. The CLI's oneway release prints it. |
x-oneway-retries | Request | 0–3. Retries each provider with a short backoff before moving on. |
x-oneway-fallback | Request | Up to three model IDs, comma-separated, tried in order if the first model fails. |
x-request-id | Response | The request's ID. Search for it under Requests. |
x-oneway-model | Response | The model that answered (differs from yours after a fallback). |
x-oneway-provider | Response | The provider that served it. |
x-oneway-attempts | Response | How many calls it took, including retries and fallbacks. |
x-oneway-budget-warning | Response | Set when a soft budget is passed: over-monthly-budget or over-department-budget. |
Failed attempts aren't charged: you pay for the call that answered, at that model's price.
Controlling spend
Limits stack; the tightest one wins.
- Balance. One prepaid USD balance for the whole organisation. Requests stop when it runs out. Top up on Billing.
- Project budget. A monthly amount on each project. Without a hard cap you get the
x-oneway-budget-warningheader; with one, requests stop. - Department allocation. A team's monthly share of the balance, set on Departments. Leads get an email at 80% and 100%.
- Personal limit. A monthly cap on one person's personal keys, always a hard stop.
- Revoking a key or changing a budget reaches the gateway at once.
Errors and limits
Errors use OpenAI's error shape (Anthropic's on /v1/messages), with ONEWAY's reason in error.code.
| STATUS | CODE | WHAT TO DO |
|---|---|---|
| 400 | invalid_request_error | The body isn't valid JSON, a header or field is malformed or unsupported (such as background responses), or the provider refused the request. The message says which. |
| 400 | format_unsupported | That model can't be called on this endpoint. Use /v1/chat/completions. |
| 401 | authentication_error | No API key was sent. Send it as Authorization: Bearer, or as x-api-key on /v1/messages. |
| 401 | invalid_api_key | The key is wrong or revoked. Check it was copied whole; a new key can take a minute to work after a failed try. |
| 401 | expired_api_key | The key has passed its expiry date. Create a new one on the project. |
| 401 | provider_key_rejected | Your provider turned down the key saved under Provider keys. Replace it there. |
| 402 | budget_exceeded | The project hit its hard-capped monthly budget. Raise the budget on the project. |
| 402 | department_budget_exceeded | The department's monthly allocation is used up. Ask its lead. |
| 402 | personal_limit_exceeded | Your personal monthly limit is reached. Ask your department lead. |
| 402 | organization_limit_exceeded | The organisation's monthly limit, set by ONEWAY support, is reached. |
| 402 | insufficient_balance | The ONEWAY balance is too low. Not returned while you use your own provider keys. |
| 403 | provider_key_missing | Add a key for that model's provider under Provider keys. |
| 403 | model_not_allowed | The model isn't enabled for this organisation. Contact support. |
| 403 | organization_suspended | Contact ONEWAY support. |
| 403 | custom_provider_unmetered | Your own providers' models have no price in ONEWAY, so a key under a hard limit can't call them. Use a key without one. |
| 404 | model_not_found | No such model ID, or a fallback model is wrong. GET /v1/models lists them. |
| 404 | custom_provider_not_found | No provider by that name under Provider keys, Other providers. Check custom/<name>/<model>. |
| 404 | not_found_error | Unknown path. Check the base URL ends in /v1. |
| 413 | body_too_large | Request bodies are limited to 4 MB. Send large files by URL, not inline. |
| 429 | rate_limit_error | Too many requests for the key, the organisation, your IP or the provider. Back off and retry. |
| 500 | server_error | A fault on our side. Retry, and send support the x-request-id. |
| 502 | upstream_error | The provider returned an error. Retry, or send x-oneway-fallback. |
| 502 | upstream_unreachable | The provider couldn't be reached. Retry, or send x-oneway-fallback. |
| 503 | provider_paused | The model is briefly unavailable. Retry shortly, or send x-oneway-fallback. |
| 503 | traffic_paused | ONEWAY is paused for maintenance. The message says more; retry shortly. |
Every response carries x-request-id. Look it up under Requests, or send it to support. Retry 429, 502 and 503 with backoff; other errors won't succeed on a retry.
| LIMIT | VALUE |
|---|---|
| Requests per API key | 600 a minute |
| Requests per client IP | 1,200 a minute |
| Request body | 4 MB |
| x-oneway-fallback | 3 models |
| x-oneway-retries | 0 to 3 |
| Attribution header values | 1–128 letters, digits and . _ : @ / - |
Roles
Set per person on Members. Yours is highlighted.
| ROLE | CAN |
|---|---|
| ownerYOU | Everything, including billing and deleting the organisation. Needs 2FA. |
| adminYOU | Projects, keys, members, departments and the audit log. Sees billing, can't pay. Needs 2FA. |
| developerYOU | Creates projects and keys, reads usage and requests (with prompts, if logged). |
| billingYOU | Adds credits, manages department allocations, reads usage. |
| viewerYOU | Reads usage and requests. Changes nothing. |
| memberYOU | Only their own keys and usage under My usage; a department lead also manages their department. |
The CLI
Everything on this dashboard from your terminal, your AI assistant, or in plain English.
npx @oneway-ai/cli init # sign in, link this folder to a project, put a key in .env.local oneway # interactive: /dashboard /usage /members /departments …, questions oneway dashboard # this overview, with the daily spend chart oneway usage --chart requests # spend, requests or latency per day oneway usage --by release --since 7d # by model, project, customer, feature, agent, release, key oneway requests tail # new requests as they land oneway keys create | rotate | revoke <id> oneway budget set 50 --hard # monthly budget, hard cap oneway topup 25 # add credit: pay in the browser oneway members invite dev@acme.com --role developer oneway departments add Research dev@acme.com --limit 50 oneway me | leaderboard | audit | devices | providers | logs oneway ask "why did spend jump yesterday?" claude mcp add oneway -- npx @oneway-ai/cli mcp # let Claude Code, Cursor or Codex manage ONEWAY
Sign-in works like gh auth login: approve the code in your browser. Signed-in terminals are listed on Security. The assistant and MCP tools never see API keys, and every change they propose waits for your OK; the audit log marks them agent and mcp.
Security
Why the dashboard sometimes asks again.
- Owners and admins need two-factor authentication before creating keys, changing members or billing. Turn it on under Security.
- Those actions also need a sign-in in the last 10 minutes. If asked, sign in again and repeat the action.
- Passkeys sign you in with your fingerprint, face or device PIN, and can't be phished.
- Prompts and responses are not stored unless an owner or admin turns it on under Requests, for 1, 7 or 30 days.