Quickstart
Flow AI is an OpenAI-compatible API. Point any OpenAI SDK at our base URL and use your Flow AI key — every request is routed to the cheapest model that can do the job.
from openai import OpenAI
client = OpenAI(
base_url="https://api.flowaiapi.com/v1",
api_key="fa-...", # from your dashboard
)
r = client.chat.completions.create(
model="flow-1", # Flow's model — routes to the cheapest capable supply for you
messages=[{"role": "user", "content": "Summarize this ticket: ..."}],
)
print(r.choices[0].message.content)
print(r.model_dump()["_flowaiapi"]) # which model served it, price, your costcurl https://api.flowaiapi.com/v1/chat/completions \
-H "Authorization: Bearer fa-..." \
-H "Content-Type: application/json" \
-d '{"model":"auto","messages":[{"role":"user","content":"hello"}]}'Authentication
Pass your API key as a bearer token: Authorization: Bearer fa-.... Create and manage keys (and per-key budgets) in the dashboard. A key is shown in full only once at creation — store it securely. New accounts get a 7-day free trial; after that an active membership ($4.99/mo or $45/yr) is required to make requests.
Chat completions
POST /v1/chat/completions — accepts the standard OpenAI request body (messages, max_tokens, temperature, tools, response_format, stream, …) and returns the standard OpenAI response shape plus a _flowaiapi block. Both streaming (SSE) and non-streaming are supported.
Flow AI adds two optional fields:
| Field | Values | Meaning |
|---|---|---|
route_strategy | auto · cascade · cheapest · balanced · fastest · <model_id> | Default auto runs the cascade: serve the cheapest capable model, judge the output, and escalate to a stronger model only if it fails. cheapest is single-shot. A concrete model id pins it. |
task_hint | free string (e.g. code) | Helps the classifier choose a capable model. |
priority / X-FlowAI-Priority header | latency | The fast lane for synchronous, user-facing calls: routes to the fastest-decode models and never to slow/free tiers. Big structured outputs (response_format: json_object + max_tokens ≥ 1000) get the fast lane automatically. |
| images | image_url parts | Base64 data URIs recommended. Remote http(s) URLs are auto-fetched by the gateway (8s timeout, 5MB cap) and inlined; a failed fetch returns a clear 400. |
Routing
On each request Flow AI classifies the task with cheap, non-LLM heuristics (length, code, tool/JSON schema, multimodal parts), then picks the cheapest model whose capabilities cover the task — looked up against the live per-minute price. So a vision prompt goes to a multimodal model, a long-context prompt to a 1M-context model, and plain text to the cheapest capable one. The decision is cached by system prompt, so agent traffic pays near-zero routing overhead.
Cascade (default). Rather than guess upfront, auto serves the cheapest capable model, runs a fast judge over the output (empty / refusal / malformed-JSON checks), and escalates to a stronger model only if it fails — you pay cheap by default and only pay up when the task actually needs it. Rejected cheap attempts aren't charged. The _flowaiapi.cascade array shows each tier tried. If a provider errors, it also fails over to the next capable one (failover: true).
Response metadata
Every non-streamed response includes a _flowaiapi object so the route is fully transparent:
"_flowaiapi": {
"seller_id": "api:deepseek-v4-flash",
"model_used": "deepseek-v4-flash",
"input_tokens": 412, "output_tokens": 188,
"clearing_price_per_1k_in": 0.00014,
"clearing_price_per_1k_out": 0.00028,
"cost_usd": 0.0000934,
"buyer_charge_usd": 0.0000962,
"interval_id": 29695141,
"routing_reason": "auto__cheapest_capable",
"latency_ms": 885,
"failover": false,
"budget_alerts": []
}You pay cost_usd × 1.025 (buyer_charge_usd) — the model's pass-through cost plus a flat 2.5% spread. The commercial price is always the ceiling.
Models
GET /v1/models lists the currently available models. You can pin one by passing its id as model or route_strategy, but auto is recommended — it tracks price changes for you. For strict, guaranteed pinning (experiments, model panels) see Panel Mode.
Panel Mode — pinned models
Routing by default, any model on demand. Flow AI's default product is smart routing — flow-1 picks the cheapest capable model for every request. But some workloads need a specific model, or a panel of genuinely different ones: judge ensembles, consensus scoring, cross-model evals, A/B model tests, reproducible research. Panel Mode is strict, opt-in pinning for exactly those cases.
Enable it per key in the dashboard (Keys → "Panel Mode"). It's off by default — leave agent keys off, since routing is what saves you money.
The contract
| Guarantee | What it means |
|---|---|
| Exact serve | A pinned request is answered by exactly the model you pinned. No cascade, no failover. |
| Truthful echo | _flowaiapi.served_model is the real upstream model string (e.g. claude-sonnet-4-5-20250929). Never a silent substitution. |
| Fail loud | Unknown model → 400. Pinned model can't serve → 503 model_unavailable. Never a fallback answer from a different model. |
| Fresh calls | Pinned requests bypass all response caching — each call really hits the model, so experiments reproduce. |
| Real-rate billing | Each pinned request bills at that model's actual rate. A 5-model panel bills 5 distinct rates. |
Pin a single model
Prefix the model id with pin: — or send the header X-FlowAI-Route: pinned with a plain model id. Accepts a registry id (gpt-4o-mini) or a provider-prefixed name (openai/gpt-4o-mini).
curl https://api.flowaiapi.com/v1/chat/completions \
-H "Authorization: Bearer fa-..." -H "Content-Type: application/json" \
-d '{"model":"pin:gpt-4o-mini","messages":[{"role":"user","content":"..."}]}'
# -> _flowaiapi: { "served_model": "gpt-4o-mini", "pinned": true, ... }The pinnable catalog: GET /v1/models?pinnable=true — id, provider, family, context window, per-token price, capabilities.
Fan out a panel — POST /v1/panel
One prompt across up to 10 pinned models in a single call. Legs run concurrently (a 5-model panel takes about as long as its slowest model), each leg bills at its own model's rate, and a model that can't serve returns an error entry while the rest still answer.
curl https://api.flowaiapi.com/v1/panel \
-H "Authorization: Bearer fa-..." -H "Content-Type: application/json" \
-d '{"models":["gpt-4o-mini","gemini-2.5-flash","claude-sonnet-4.6"],
"max_tokens":256, "temperature":0,
"messages":[{"role":"user","content":"Would you cite this source? ..."}]}'{
"object": "panel.result",
"results": [
{ "model": "gpt-4o-mini", "status": "ok", "served_model": "gpt-4o-mini",
"message": {"role":"assistant","content":"..."}, "usage": {...},
"cost": {"buyer_charge_usd": 3.1e-06, "rate_per_1k_in": 0.00015, "rate_per_1k_out": 0.0006},
"latency_ms": 812 },
{ "model": "gemini-2.5-flash", "status": "ok", ... },
{ "model": "claude-sonnet-4.6", "status": "ok", ... }
],
"summary": { "requested": 3, "ok": 3, "failed": 0, "total_charge_usd": 0.00012 }
}Shared parameters (messages, max_tokens, temperature, top_p, response_format, tools, stop, seed) apply to every leg. An unknown model anywhere in the list fails the whole call with 400 — a partial panel you didn't ask for is never run. Non-streaming only. Panel Mode errors: 403 — not enabled for this key · 400 — unknown model · 503 — pinned model unavailable (never a fallback).
Quick setup for agent frameworks
Flow AI is a drop-in backend for any agent stack — Paperclip, Hermes, OpenClaw, Claude Code, Codex, and anything OpenAI- or Anthropic-compatible. You only change the base URL and the API key; pass auto as the model and Flow AI picks the cheapest capable model per request. Pick the block that matches your framework's protocol:
Anthropic protocol — Claude Code, OpenClaw, Paperclip (claude_local)
export ANTHROPIC_BASE_URL="https://api.flowaiapi.com"
export ANTHROPIC_AUTH_TOKEN="fa-..." # your Flow AI key (also accepted: ANTHROPIC_API_KEY / x-api-key)
# model: pass "auto" (any Claude model name also works and auto-routes)OpenAI Chat protocol — Hermes, LangChain, opencode, most SDKs
export OPENAI_BASE_URL="https://api.flowaiapi.com/v1"
export OPENAI_API_KEY="fa-..."
# model: "flow-1" (Flow's model — routes to the cheapest capable supply; "auto" also works)OpenAI Responses protocol — Codex CLI (v0.132+)
model = "auto"
model_provider = "flowai"
[model_providers.flowai]
name = "Flow AI"
base_url = "https://api.flowaiapi.com/v1"
wire_api = "responses"
env_key = "FLOWAI_KEY" # then: export FLOWAI_KEY=fa-...| Framework | Use the block | Endpoint |
|---|---|---|
Paperclip — claude_local | Anthropic | /v1/messages |
Paperclip — opencode / OpenAI adapter | OpenAI Chat | /v1/chat/completions |
Paperclip — codex_local | Responses | /v1/responses |
| Hermes | OpenAI Chat | /v1/chat/completions |
| OpenClaw | Anthropic | /v1/messages |
| Claude Code | Anthropic | /v1/messages |
| Codex CLI | Responses | /v1/responses |
All three protocols support full tool-calling, streaming, and multi-turn loops, so agents do real work — see below. An active membership + balance are required (top up in the dashboard).
Tool calling & agents
Flow AI speaks all three major agent protocols with full tool-calling parity — point your framework at the matching endpoint and Flow's routing, failover, ledger, and tool handling all apply. Unknown model ids auto-route to the cheapest capable model.
| Framework | Endpoint | Auth header |
|---|---|---|
| OpenAI SDK / LangChain / etc. | POST /v1/chat/completions | Authorization: Bearer fa-… |
| Claude Code · Claude Agent SDK | POST /v1/messages | x-api-key: fa-… |
| Codex CLI (v0.132+) | POST /v1/responses | Authorization: Bearer fa-… |
All three accept tools, return tool calls, and accept tool results on follow-up turns, in both streaming and non-streaming modes — so multi-step agents complete real work, not just text.
Anthropic Messages
Anthropic-style clients use POST /v1/messages with the key as an x-api-key header. Full tool support: Anthropic tools (input_schema) and tool_choice are translated to the router's function-calling; responses return tool_use content blocks with stop_reason: "tool_use", and tool_result blocks on the next turn continue the loop. Streaming emits protocol-correct Anthropic SSE (incl. input_json_delta for tool input). Point Claude Code at it with ANTHROPIC_BASE_URL.
curl https://api.flowaiapi.com/v1/messages \
-H "x-api-key: fa-..." -H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"auto","max_tokens":256,
"tools":[{"name":"get_weather","description":"Get weather",
"input_schema":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}],
"messages":[{"role":"user","content":"Weather in Tokyo? Use the tool."}]}'
# -> stop_reason: "tool_use", content: [{"type":"tool_use","name":"get_weather","input":{"city":"Tokyo"}}]OpenAI Responses
POST /v1/responses implements the OpenAI Responses API, which the current Codex CLI requires. It accepts input (a string or an array of message / function_call / function_call_output items), instructions, flattened tools, tool_choice, and max_output_tokens, and returns output items (message with output_text, and function_call). Streaming emits the Responses event set (response.created → output_item.added → output_text.delta / function_call_arguments.delta → response.completed).
curl https://api.flowaiapi.com/v1/responses \
-H "Authorization: Bearer fa-..." -H "Content-Type: application/json" \
-d '{"model":"auto","max_output_tokens":256,
"tools":[{"type":"function","name":"get_weather","description":"Get weather",
"parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}],
"input":"Weather in Tokyo? Use the tool."}'
# -> output: [{"type":"function_call","name":"get_weather","arguments":"{\"city\":\"Tokyo\"}"}]For Codex, set the base URL to https://api.flowaiapi.com/v1 and your fa-… key.
Errors
| Status | Meaning |
|---|---|
401 | Missing or invalid API key. |
402 | Membership inactive, or insufficient balance — top up to continue. |
429 | Rate limit or per-key budget exceeded — back off and retry (honor Retry-After). |
502 | All capable providers failed for this request. |