Introduction
Kafox is an AI gateway compatible with the OpenAI API: one key, one endpoint and many models. Swap the base URL and the key in your SDK, keep the same request body, and your balance, in Brazilian reais (BRL), is charged on every response.
Request flow
Quickstart
-
Create a key
In API Keys, create a
kafox_live_...key. The secret is shown only once, so save it before closing the dashboard. The dashboard is currently available in Portuguese only. -
Point to the base URL
Use
https://api.kafox.dev/v1instead ofhttps://api.openai.com/v1. Nothing else changes. -
Send the request
A
POST /chat/completionswithmodelandmessagesreturns the answer and charges the tokens. Thekafox-freemodel in the example is free and works even with a zero balance.
kafox-free and the ones
ending in (free)) keep answering with a zero balance, within the
daily quota. See Limits and
Balance and billing.
Authentication
Every call carries the key in the Authorization header. The key
identifies which account pays for the request.
Authorization: Bearer kafox_live_xxxxxxxx
Content-Type: application/json
The X-Api-Key: kafox_live_xxxxxxxx header is also accepted, for
clients that do not let you customize Authorization.
- A missing, invalid or revoked key returns
401. See Errors. - No balance returns
402before the model is called, and nothing is charged. Free models go through anyway. - One key per project keeps usage history separate and lets you revoke a key without changing your password. Each account can have up to 10 active keys.
- Never put the key in browser code or in a distributed app. Call Kafox from your server and, if a key leaks, revoke it in API Keys.
- The secret is shown only once. We store only a hash of it.
API Tester
Run a real call without leaving the browser. The key stays in this tab's memory only: it is not saved or logged.
Create one in API Keys. The key is used for this call only.
curl
// fill in the key and click Run
Chat completions
/chat/completions
Same body and same response as OpenAI. It supports SSE streaming, tool calling and images on vision models.
| Field | Type | Description |
|---|---|---|
model | string | Required. An id from the models list, kafox-free or an alias (fast, smart). |
messages | array | Required. A list of { role, content } with system, user, assistant and tool. content can be text or a list of text and image_url parts. |
stream | boolean | Returns the answer as SSE events, token by token. |
stream_options | object | With { "include_usage": true } the last event carries the response usage. |
temperature | number | From 0 to 2. Lower is more predictable. |
max_tokens | number | Cap on generated tokens. |
tools, tool_choice | array, string | Tool calling in the OpenAI format. |
Other OpenAI-format fields are passed through to the model. Not every
model accepts all of them: an unsupported field may be ignored or return
400.
{
"id": "chatcmpl-7e39862f-9c53-49ce-bbc3-fcaf38c5f913",
"object": "chat.completion",
"created": 1793593191,
"model": "deepseek-ai/DeepSeek-V4.1-Flash",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Hello! How can I help?" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 18, "completion_tokens": 9, "total_tokens": 27 }
}
Response headers
| Header | Value |
|---|---|
X-Request-Id | Call identifier. Give it to support if you need something investigated. |
X-PyFlow-Cache | miss, exact or semantic: whether the answer came from the gateway cache. |
X-Kafox-Model | Only on kafox-free: the model that actually answered. |
Streaming
With "stream": true the answer arrives as SSE events
(data: {...}, separated by a blank line) and ends with
data: [DONE]. Ask for stream_options.include_usage
to get the consumption in the last event.
data: {"object":"chat.completion.chunk","model":"...","choices":[{"index":0,"delta":{"role":"assistant","content":"Hel"}}]}
data: {"object":"chat.completion.chunk","model":"...","choices":[{"index":0,"delta":{"content":"lo!"},"finish_reason":"stop"}]}
data: {"object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":21,"completion_tokens":9,"total_tokens":30}}
data: [DONE]
- Reasoning models send their thinking in
delta.reasoning_content(ormessage.reasoning_contentwithout streaming) before thecontent. Those tokens count toward usage. With a very lowmax_tokensthe model can spend everything thinking and return a nullcontentwithfinish_reason: "length". - Error in the middle of a stream: if the model fails after it has started, you get an
{"error":{"message":"...","type":"api_error","code":"upstream_error"}}event instead of an HTTP status, because the200was already sent.
Tool calling
tools and tool_choice follow the OpenAI format. The
model returns tool_calls; run the function and reply with a
role: "tool" message carrying the matching
tool_call_id. Not every model supports tools.
- Fallback: if one route fails, the next one takes over silently. The answer still comes from the same key, in the same format.
- Cache: repeated prompts can be answered by the gateway cache (
exact, orsemanticwhen the question is similar enough). TheX-PyFlow-Cacheheader tells you what happened.
Models
/models
Lists the model ids your key can use. Always send the exact id:
deepseek-ai/DeepSeek-V4.1-Flash, not just
deepseek.
{
"object": "list",
"data": [
{ "id": "deepseek-ai/DeepSeek-V4.1-Flash", "object": "model", "created": 1793593191, "owned_by": "kafox" },
{ "id": "kafox-free", "object": "model", "created": 1793593191, "owned_by": "kafox" },
{ "id": "openai/gpt-oss-120b (free)", "object": "model", "created": 1793593191, "owned_by": "kafox" }
]
}
kafox-freeis a virtual model: it picks an available free model on its own and switches route if one is limited.- Ids ending in
(free)are specific free models. Use the full name, suffix included. - The
fastandsmartaliases are accepted in themodelfield but are not in the list. - Prices are not in this response: they are at
GET https://kafox.dev/api/public/pricing, public and keyless. Values are integer micro-reais per million tokens (input_micros_per_1m,cached_micros_per_1m,output_micros_per_1m); R$ 1 = 1,000,000.
Errors
Errors arrive as JSON in the OpenAI format. code is the HTTP
status itself, and type tells you where the error came from.
{
"error": {
"message": "chave de API invalida",
"type": "http_error",
"code": 401
}
}
The message text is currently written in Portuguese. Rely on
code and type in your code, not on the text.
| Status | Type | What it means and what to do |
|---|---|---|
400 | gateway_error, invalid_request_error | Invalid JSON, missing model or messages, or a field outside the format. Fix the request; retrying will not help. |
401 | http_error | Missing, invalid or revoked key. Check the header and your keys in API Keys. |
402 | http_error | Insufficient balance. Top up in Credits. Free models keep working. |
404 | gateway_error | The requested model does not exist or is unavailable. Check the id with GET /models. |
429 | rate_limit_error, gateway_error | The key's request limit or the day's free quota was reached. Wait for the time in the Retry-After header. See Limits. |
500 | internal_error | Internal gateway error. Try again; if it persists, contact support with the X-Request-Id. |
502 | gateway_error | No route managed to answer. Try again in a moment. |
503 | gateway_error | Service temporarily unavailable. Try again in a moment. |
- Retry (with growing waits) only on
429,500,502and503.400,401,402and404do not fix themselves. - Error messages never mention the upstream provider.
Limits
Each key has a per-minute and per-hour request limit, and each account has a daily quota of free tokens.
| Limit | Value | When it is hit |
|---|---|---|
| Requests per minute | 60 per key | 429 rate_limit_error with Retry-After in seconds. |
| Requests per hour | 2000 per key | Same as above. |
| Free tokens per day | 5,000,000 per account | 429 until midnight UTC. |
| Active keys | 10 per account | Revoke a key you no longer use to create another. |
- The request values are the default for keys without their own limit. A key can have custom limits.
- Limits count requests, not tokens, and use sliding windows:
Retry-Aftertells you how many seconds until a slot opens. - The free quota is one per account (creating more keys does not raise it): it adds up every free model used in the day, it is not per model. It resets at midnight UTC.
Balance and billing
The balance is prepaid, in Brazilian reais (BRL), and is charged on every response according to the tokens used. Credits do not expire.
- How cost is computed: input tokens × input price + output tokens × output price, per million tokens. The part of the prompt the provider served from its own cache is billed at the much lower cache rate. Each model's prices are in Models and pricing.
- Top up by PIX (Brazil's instant payment system) in Credits, from R$ 5. Packages are R$ 5, 10, 25, 50 and 100, and you can also choose a custom amount.
- Welcome bonus: each account's first paid top-up of at least R$ 5 gets another R$ 5 as a bonus, once.
- Zero balance: calls to paid models return
402before the model is called, and nothing is charged. Free models keep working within the daily quota. - Where to see your balance: in the dashboard, or in the terminal with
kafox balance.
Models and pricing
Values in Brazilian reais (BRL) per 1 million tokens. The dashboard uses this same table to compute the cost of each call.
| Model | Input / 1M | Cache / 1M | Output / 1M |
|---|---|---|---|
| Loading table... | |||
Free tier: models marked free do not
use your balance. Each account gets 5 million free tokens per
day across all free models (not per model), resetting at
midnight UTC. Use "model": "kafox-free" and Kafox picks a free
model and switches route when one is limited.
The same table as JSON, for scripts: GET https://kafox.dev/api/public/pricing.
Terminal CLI
Kafox also lives in the terminal. The CLI is a full TUI: streaming, reasoning, file editing with diffs, shell tools, MCP and subagents, all on your account and billed as tokens.
Installation
npm install -g https://kafox.dev/static/downloads/kafox-cli-latest.tgz
Requires Node.js 22.5 or newer. The same command updates to
the newest version, and kafox --version
shows which one is installed. Releases live in
/static/downloads/, one file each
(kafox-cli-<version>.tgz).
First steps
-
Sign in
kafox loginshows a short code and a link. Confirm in the browser and the session is saved in~/.kafox/. -
Open the TUI
Just
kafoxopens the interface in the current folder, which becomes the project. Pick the model with/model. -
Or run without the interface
kafox agent "review src/ and point out bugs"runs without the TUI, good for CI, scripts and automated audits.
Terminal commands
kafox opens the TUI
kafox login | logout sign in or out
kafox whoami | status account, balance and gateway
kafox models models and prices per 1M tokens
kafox balance | pricing balance and top-up packages
kafox key creates an API key
kafox ask "question" [-m model]
kafox agent "goal" [-y] [--max-steps N] [--json]
kafox -p "prompt" [-y] [--output-format json] headless mode (scripts and CI)
kafox history [n] saved conversations
kafox resume [code] resumes a conversation
kafox continue | -c back to the most recent conversation
kafox theme | background theme and background image
kafox provider alternative providers (external keys)
kafox mobile use the CLI from your phone via QR Code
kafox update [--check] updates the CLI (verifies the SHA-256 before installing)
kafox doctor diagnoses login, API, model, git, sandbox, MCP and version
kafox --allow-all | -y starts with every tool pre-approved
kafox --version | --help
Commands inside the TUI
Type / to open the menu (arrows navigate, Tab completes, Enter runs).
| Command | What it does |
|---|---|
/model, /models | Pick the model, or directly with /model <id>. |
/balance, /pricing, /status | Balance, top-up packages, account and gateway. |
/allow | Auto-approval for this session; /allow off goes back to asking. |
/image, /paste | Attach an image to the next turn (file or clipboard). |
/copiar | Copies the whole last answer. |
/mouse | Turns the mouse wheel on or off (when off, the terminal selects text). |
/mcp | Lists MCP servers and tools; /mcp reload reconnects. |
/agents, /queue | The session's subagents and the message queue. |
/theme, /background | Theme and background image. |
/compact, /clear | Compacts or clears the context. |
/key, /login, /logout, /whoami, /exit | Account and exit. |
Shortcuts
- Enter queues a message while the AI is working; Esc twice interrupts the current step.
- Ctrl+V or Alt+V paste a copied image (screenshot) as an attachment, with side-by-side previews and a button to remove each one. If your terminal swallows Ctrl+V, use
/paste. - Ctrl+Y copies the last answer; PgUp/PgDn and the mouse wheel scroll the conversation.
- F2 toggles the mouse wheel. To select text while the wheel is on, hold Shift (Option on macOS) and drag.
Headless mode (scripts and CI)
With -p (or --print) the CLI runs a single task without opening the interface and returns the result.
Use it in scripts, automations and pipelines. Available from version 0.12.
kafox -p "summarize the README" prints only the final answer
echo "explain this error" | kafox -p prompt from stdin
git diff | kafox -p "review this change" argument + stdin together
kafox -p "run the tests" -y --output-format json one JSON object at the end
kafox -p "analyze the project" --plan read-only
| Option | What it does |
|---|---|
--output-format text|json|stream-json | text (default) prints only the answer. json prints one object at the end. stream-json prints one object per line for each event. |
-y, --allow-all | Approves writes and command execution. Without it the AI can only read; anything that needs approval is refused. The blocked-command lists still apply. |
--plan | Read-only: the AI plans and changes nothing. |
--max-turns N | Agent step limit (default 25). |
--max-custo R$ | Stops when the run's spending passes the amount. The balance is checked after each step, so spending can slightly exceed the cap. |
-m, --model | Model for the run. |
--cwd folder | Working folder. |
-c, --continue, --resume code | Continues the latest conversation or a saved one. |
--no-memory | Does not load KAFOX.md or AGENTS.md. |
With the json format the object has result, model, session_id, is_error, usage, cost_brl, duration_ms, turns and tool_calls
(plus error on failure). In the JSON formats stdout contains only JSON; warnings and errors go to stderr.
| Exit code | Meaning |
|---|---|
0 | Task completed. |
1 | Task or model error, step limit reached or budget exceeded. |
2 | Invalid usage or not logged in (kafox login). |
3 | A tool was refused for lack of approval or because it is blocked. |
130 | Interrupted (Ctrl+C or SIGTERM). Processes the run started are stopped. |
Example CI step (GitHub Actions) that reviews a pull request:
- name: Review with Kafox
env:
KAFOX_HOME: ${{ runner.temp }}/kafox
KAFOX_TOKEN: ${{ secrets.KAFOX_TOKEN }}
run: |
npm i -g https://kafox.dev/static/downloads/kafox-cli-latest.tgz
mkdir -p "$KAFOX_HOME" && echo "$KAFOX_TOKEN" > "$KAFOX_HOME/token.json"
git diff origin/main...HEAD | kafox -p "review this change and list problems" --plan --max-custo 1 > review.md
In CI there is no browser to log in: run kafox login once on your own machine and store the contents of ~/.kafox/token.json as a pipeline secret (KAFOX_TOKEN in the example). The session expires; renew the secret when needed.
MCP servers defined in the project folder do not start in headless mode, because nobody can approve them.
Version 0.11 features
Available from CLI 0.11 on. Check yours with
kafox --version and update with
kafox update.
| Command | What it does |
|---|---|
/memory, /init | Shows the loaded project memory; /init asks the AI to analyze the project and write KAFOX.md (it goes through write approval). |
/plan | Plan mode: the AI only reads and proposes a plan. /plan aprovar runs it and /plan off leaves plan mode. |
/undo, /undo turno, /checkpoints | Undoes the AI's last file change, or all changes of the last turn, and lists what can be undone. |
/permissoes | The project's allowed and blocked commands (allow, deny, remove). |
/custo | Cost of the conversation and of the session (also in the footer). |
/diff, /commit, /branch | Git: changes, a commit whose message the AI proposes and you approve, and switching or creating a branch. |
/sandbox on|off | Isolates the AI's commands (Linux and macOS). |
/auto on|off | Automatic model choice: cheap for simple tasks, strong for hard ones. |
/doctor, /update | Diagnostics and a check for a newer version. |
- Project memory: create a
KAFOX.md(orAGENTS.md) at the project root with what the AI needs to know: how to run the tests, conventions, cautions. A~/.kafox/KAFOX.mdapplies to every project. The files go into the prompt on every message (up to 12,000 characters per file and 24,000 in total) and the interface tells you when it loaded one. A file from a third-party repository is untrusted content: read it before opening unknown projects. - Checkpoints: before every
write_fileoredit_filethe CLI saves the file's previous state in~/.kafox/checkpoints/, outside the project. Limit of 300 points per project; files above 5 MB are not saved. - Permissions:
.kafox/permissions.json(project) and~/.kafox/permissions.json(global) listallowanddeny, with*matching any text. A blocked command never runs, not even with--allow-all. An allowed command only skips the prompt when every part of it is on the list. - Sandbox: uses
bwrap(Linux) orsandbox-exec(macOS): commands can only write to the project folder,/tmpand the caches. With the sandbox on but unavailable, the command does not run. Windows has no simple equivalent, so it stays off. - Automatic model: short questions go to the cheap model (default
kafox-free); code, bugs, refactoring, several files, images and long requests go to the strong one. Picking a model with/modelturns automatic mode off. - Live cost: the footer shows the conversation and session spend, and your balance. A free model shows as free.
What the agent does
- Reads and edits files (
read_file,list_dir,write_file,edit_file), with the diff in the conversation. Every path is locked inside the project directory. - Runs commands (
run_command). Anything that writes, edits or executes asks for approval: allow once, allow always or deny. - A command that does not finish (server, watcher, loop) moves to the background after about 60 s: the agent keeps working and checks or stops the process later (
process_output,stop_process,list_processes). - Launches subagents in parallel to investigate several points, and calls tools from configured MCP servers.
- If the network drops, it retries on its own with growing waits; Esc cancels the wait. Conversations are saved in
~/.kafox/chats/and come back withkafox resume.
MCP
Configure it in ~/.kafox/mcp.json (or
./mcp.json in the project, which wins). The
tools appear in the agent as mcp__server__tool. Servers from a
project's mcp.json only start after you approve them: the CLI shows
each command and you choose to approve once, approve always for that folder, or
decline (/mcp aprovar shows the prompt again). If the file changes,
it asks again. Servers from your personal config in ~/.kafox start
on their own.
{
"mcp": {
"playwright": {
"type": "local",
"command": ["npx", "-y", "@playwright/mcp@latest"]
},
"remote": {
"type": "remote",
"url": "https://example.com/mcp",
"headers": { "authorization": "Bearer ..." }
}
}
}
Configuration
The session and preferences live in ~/.kafox/
(or in the folder pointed to by KAFOX_HOME).
KAFOX_API_URL changes the API and
KAFOX_ALLOW_ALL=1 starts with the tools
pre-approved. The CLI only answers with a balance, or with a free model.
Node.js
The official OpenAI SDK for JavaScript and TypeScript. Install it, swap the base URL and the key.
npm install openai
Python
The official OpenAI SDK for Python 3.8+. The same client.chat.completions as OpenAI.
pip install openai
PHP
openai-php/client, the most used community client. Works with PHP 8.2+.
composer require openai-php/client
Frequently asked questions
Which SDK should I use?
Any OpenAI-compatible client: the official Python and Node.js SDKs, openai-php, or plain HTTP. Only the base URL and the key change.
Do I need a balance to try it?
No. kafox-free and the models with (free) do not use your balance. The quota is 5 million tokens per day per account and resets at midnight UTC.
I got a 402. Now what?
Your balance ran out. Top up by PIX in Credits; the minimum is R$ 5. Meanwhile, free models keep answering.
I got a 429. What does it mean?
Either the key went over its per-minute or per-hour request limit, or the day's free quota is used up. Wait the number of seconds in the Retry-After header and try again. See Limits.
Do streaming, tools and images work?
Yes. SSE streaming, tools and image_url follow the OpenAI format. Tools and images depend on the model you pick: a model without vision does not accept images.
Why did the answer come back empty?
On reasoning models, the thinking consumes max_tokens. Raise the limit, or also read the reasoning_content field.
How do I reach support?
By email at [email protected], or through the community on Discord, which also has support tickets. Include the X-Request-Id of the failed call.
Is this documentation available to AIs?
Yes, as plain text in the llm.txt format.