OpenAI-compatible API gateway for https://chat.sakana.ai.
It reverse-engineers the Sakana Chat web API and exposes it as a standard /v1/chat/completions endpoint, so you can use Sakana agents with any OpenAI-compatible client (OpenAI Python/JS SDK, ChatGPT-Next-Web, LobeChat, etc.).
- OpenAI-compatible endpoints
GET /v1/modelsGET /v1/models/{model_id}POST /v1/chat/completions(streaming & non-streaming)
- Automatic model discovery via Sakana's
/api/agents - Supports all Sakana Chat agents plus tone-mode and thinking variants
.envconfiguration for session cookie, Cloudflare clearance, proxy, etc.- Automatic cookie extraction from HAR files — no manual copy/paste needed
- Runtime cookie reload / HAR upload endpoints
- Automatic cookie refresh — upstream
Set-Cookieheaders are synced back and persisted - Automatic retry on 401/429 — reloads cookies and retries with exponential backoff
- Optional gateway-level API key
- HTTP/HTTPS proxy support for upstream requests
- Thinking / planning chain exposed as
reasoning_content
- Python >= 3.10
- A Sakana Chat session cookie (
sakana-chat) from your browser
# Create a virtual environment (recommended)
python -m venv .venv
# Windows
.venv\Scripts\python -m pip install -e .
# macOS / Linux
source .venv/bin/activate
pip install -e .Copy the example environment file and edit it:
cp .env.example .envRequired:
| Variable | Required | Description |
|---|---|---|
SAKANA_SESSION |
No* | Value of the sakana-chat cookie |
SAKANA_HAR_PATH |
No* | Path to a HAR file for automatic cookie extraction |
* At least one of SAKANA_SESSION or a HAR file is required.
Optional:
| Variable | Default | Description |
|---|---|---|
CF_CLEARANCE |
- | Cloudflare clearance cookie (also auto-extracted from HAR) |
API_KEY |
- | Protect this gateway with a Bearer token |
SAKANA_BASE_URL |
https://chat.sakana.ai |
Upstream base URL |
DEFAULT_AGENT_ID |
namazu |
Fallback agent/model id |
HTTP_PROXY / HTTPS_PROXY |
- | Proxy for upstream requests. When set, SSL verification is disabled by default. |
VERIFY_SSL |
auto | true/false. Defaults to false when a proxy is configured, true otherwise. |
COOKIE_STORE_PATH |
cookies.json |
File where refreshed cookies are persisted |
MAX_RETRIES |
2 |
Retries on upstream 401/429 with cookie reload and exponential backoff |
HOST |
0.0.0.0 |
Gateway bind address |
PORT |
8000 |
Gateway port |
WORKERS |
1 |
Uvicorn workers |
REQUEST_TIMEOUT |
120.0 |
Upstream request timeout (seconds) |
Sakana Chat re-issues the sakana-chat session cookie on almost every response (sliding expiration). The gateway watches upstream Set-Cookie headers and automatically updates the runtime cookie cache, then persists it to cookies.json.
- Cookies loaded from
.envor a HAR file are used as the initial seed. - Whenever Sakana returns a new
sakana-chatorcf_clearance, it is saved toCOOKIE_STORE_PATH(default:cookies.json). - On restart, the gateway loads
.envfirst, then overlays the persistedcookies.json, so refreshed cookies survive restarts.
Note: This only extends the life of a valid session. If the upstream session is fully invalidated (401
ログインが必要です), you still need to re-export a HAR file or updateSAKANA_SESSIONmanually.
When Sakana returns 401 Unauthorized or 429 Too Many Requests, the gateway automatically:
- Reloads cookies from
.env/cookies.json/ HAR - Waits with exponential backoff (
1s,2s,4s… capped at8s) - Retries the upstream request
Configure the retry count with MAX_RETRIES (default: 2). If all retries fail, the gateway returns 502 Bad Gateway with the upstream error message.
The gateway can read cookies directly from a browser HAR file, so you don't need to copy/paste them manually.
- Open https://chat.sakana.ai in your browser and log in.
- Open DevTools -> Network -> right-click -> Save all as HAR with content.
- Put the
.harfile in the project root (or setSAKANA_HAR_PATH). - Start the gateway.
It will automatically pick up the latest sakana-chat and cf_clearance cookies from the HAR file.
# Optional: explicit HAR path
SAKANA_HAR_PATH=./chat.sakana.ai.har- Open https://chat.sakana.ai in your browser and log in.
- Press
F12-> Application (or Storage in Firefox) -> Cookies ->https://chat.sakana.ai. - Find the cookie named
sakana-chatand copy its value. - Paste it into
.env:
SAKANA_SESSION=3ff0203c-5a05-436e-a180-2060bfd00c08The cookie is usually valid for ~14 days. If requests start failing with 403/401, refresh the cookie.
# Using the installed script
sakana2api
# Or directly
python main.py
# Or with uvicorn
uvicorn sakana2api.app:app --host 0.0.0.0 --port 8000from openai import OpenAI
client = OpenAI(
api_key="not-needed", # or set to the API_KEY you configured
base_url="http://127.0.0.1:8000/v1",
)
response = client.chat.completions.create(
model="namazu", # or any model id from GET /v1/models
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"},
],
stream=False,
)
print(response.choices[0].message.content)
# Tone-mode variants are exposed as separate model ids.
# Use `namazu-jp-vibes` or `namazu-osaka` for different tones.
response = client.chat.completions.create(
model="namazu-osaka",
messages=[{"role": "user", "content": "こんにちは"}],
)stream = client.chat.completions.create(
model="namazu",
messages=[{"role": "user", "content": "Count to 5"}],
stream=True,
)
for chunk in stream:
content = chunk.choices[0].delta.content
if content:
print(content, end="")Sakana Chat exposes one agent (namazu) with several tone presets. The gateway maps these to OpenAI-style model ids:
| Model id | Agent | Tone mode | Thinking |
|---|---|---|---|
namazu |
namazu |
default |
off |
namazu-jp-vibes |
namazu |
jp-vibes |
off |
namazu-osaka |
namazu |
osaka |
off |
namazu-thinking |
namazu |
default |
on |
Combined suffixes are also supported, e.g. namazu-osaka-thinking.
When thinking is enabled, Sakana may wrap its reasoning in <think>...</think> (or <plan>...</plan>) and put the final answer after it. The gateway can expose that reasoning chain as reasoning_content:
response = client.chat.completions.create(
model="namazu-thinking",
messages=[{"role": "user", "content": "Solve 23 * 47 step by step"}],
)
print(response.choices[0].message.reasoning_content)
print(response.choices[0].message.content)To get the reasoning chain while using a non-thinking model, pass returnPlan: true:
response = client.chat.completions.create(
model="namazu",
messages=[{"role": "user", "content": "Explain quantum computing"}],
extra_body={"returnPlan": True, "returnReasoning": True},
)You can override the model-derived defaults by passing extra body fields:
response = client.chat.completions.create(
model="namazu",
messages=[{"role": "user", "content": "Explain quantum computing"}],
extra_body={
"enableThinking": True,
"toneMode": "default",
"webSearchEnabled": True,
"returnPlan": False,
"returnReasoning": True,
},
)| Option | Type | Default | Description |
|---|---|---|---|
enableThinking |
bool | false |
Enable thinking mode |
toneMode |
str | "default" |
Tone preset (default, jp-vibes, osaka) |
webSearchEnabled |
bool | true |
Allow web search |
returnPlan |
bool | false |
Request a <plan> reasoning section |
returnReasoning |
bool | true |
Include extracted reasoning in reasoning_content |
Note: Thinking mode and web search cannot be enabled at the same time upstream. When thinking is enabled, web search is automatically disabled unless you explicitly set
webSearchEnabled: true.
If API_KEY is set, these admin endpoints are protected by it.
| Endpoint | Method | Description |
|---|---|---|
POST /v1/admin/cookies |
JSON body | Set cookies at runtime (sakana_chat, sakana_session, or cf_clearance) |
POST /v1/admin/reload-cookies |
- | Reload cookies from .env / HAR file |
POST /v1/admin/upload-har |
Raw HAR bytes | Upload a new HAR and extract cookies |
Example:
curl -X POST http://127.0.0.1:8000/v1/admin/reload-cookies \
-H "Authorization: Bearer your-api-key"| OpenAI endpoint | Sakana endpoint |
|---|---|
GET /v1/models |
GET /api/agents |
POST /v1/chat/completions |
POST /conversation + POST /conversation/{id} |
The gateway creates a fresh upstream conversation for every OpenAI request and embeds the full message history in the latest user turn, keeping the OpenAI side stateless.
sakana2api/
├── sakana2api/
│ ├── __init__.py
│ ├── app.py # FastAPI routes
│ ├── config.py # .env configuration & runtime cookie cache
│ ├── cookie_loader.py # HAR / env cookie extraction
│ ├── formatter.py # OpenAI -> Sakana message conversion
│ ├── main.py # CLI entry point
│ ├── models.py # Pydantic request/response models
│ ├── openai.py # OpenAI response builders & streaming
│ ├── upstream.py # Sakana upstream HTTP client
│ └── uuid7.py # UUIDv7 generator for upstream message ids
├── main.py # Backward-compatible entry point
├── .env.example
├── pyproject.toml
└── README.md
When the upstream request fails, the gateway returns 502 Bad Gateway with a structured JSON body so you can tell what went wrong:
{
"error": {
"message": "Upstream authentication failed for /api/agents. ...",
"code": "authentication_failed",
"attempts": 3,
"upstream_status": 401,
"upstream_body": "..."
}
}code |
Meaning | Typical fix |
|---|---|---|
connection_failed |
Cannot reach Sakana (network, proxy, SSL) | Check HTTP_PROXY/HTTPS_PROXY; set VERIFY_SSL=false if your proxy inspects SSL |
authentication_failed |
Upstream returned 401 |
Refresh SAKANA_SESSION or upload a new HAR file |
rate_limited |
Upstream returned 429 |
Wait for quota reset, or use a different account/cookie |
invalid_response |
Upstream returned non-JSON or unexpected shape | Usually a temporary Sakana API change; report an issue |
upstream_error |
Any other upstream 4xx/5xx | Inspect upstream_status and upstream_body |
attempts shows how many times the gateway retried (including the initial request). MAX_RETRIES controls how many automatic retries are attempted on 401/429.
| Symptom | Cause / Fix |
|---|---|
401/403 from upstream |
SAKANA_SESSION expired or missing. Refresh the cookie from your browser. |
429 / usage limit |
The upstream account has hit its rate/conversation limit. Wait or refresh the cookie. |
| Cloudflare challenge | Add CF_CLEARANCE cookie value to .env. |
| SSL certificate errors | Set VERIFY_SSL=false if you are behind an SSL-inspecting proxy. |
| Timeouts | Increase REQUEST_TIMEOUT or check your proxy. |
| Unknown model | The model id is mapped to the Sakana agentId. Unknown ids fall back to DEFAULT_AGENT_ID. |
This is an unofficial community gateway. It is not affiliated with Sakana AI. Use at your own risk and in compliance with Sakana's Terms of Service.