Quickstart & reference
Docs
The API is OpenAI-shaped, so any OpenAI client works. Point the base URL
at api.fiferouter.com/v1, send
"model": "auto", and let the concept decide.
Quickstart
curl https://api.fiferouter.com/v1/chat/completions \
-H 'content-type: application/json' \
-H 'authorization: Bearer $FIFEROUTER_API_KEY' \
-d '{
"model": "auto",
"messages": [{"role":"user","content":"verify this refund path"}]
}'
The response is OpenAI-shaped, with one difference that matters: the
model field names the model that
actually served the request, not the one you asked for.
A router that echoes the request back cannot be audited.
With the OpenAI SDK
from openai import OpenAI client = OpenAI( base_url="https://api.fiferouter.com/v1", api_key=os.environ["FIFEROUTER_API_KEY"], ) resp = client.chat.completions.create( model="auto", messages=[{"role": "user", "content": "summarise this thread"}], extra_headers={"x-fife-session": "conv-42"}, ) print(resp.model) # the model that actually ran
Routing headers
Routing signals travel as headers, so the request body stays a plain OpenAI payload.
| Header | Effect |
|---|---|
x-fife-concept | Name the concept explicitly. Always beats classification — you know what you asked for. |
x-fife-session | Keep one conversation on one model across turns, while it still passes every filter. |
x-fife-critical | Value-bearing work. Pins residency to in_infra, whatever the ranking prefers. |
x-fife-residency | Require a residency without claiming criticality. |
What comes back
| Header | Meaning |
|---|---|
x-fife-model | The model that served it. |
x-fife-concept | The concept it was routed as. |
x-fife-rung | Which classifier rung decided: explicit, cache, embedding, llm or default. |
x-fife-attempts | How many models were tried. Above 1 means the fallback chain fired. |
Explaining a request
POST /v1/explain returns the routing decision
without calling a provider. It spends no tokens and consumes no credit, so
you can run it in CI over a corpus of real phrasing before shipping a
concept or policy change.
curl https://api.fiferouter.com/v1/explain \ -H 'content-type: application/json' \ -d '{"text":"can this retry double-charge the customer?","critical":true}' { "concept": "moneypath.verify", "confidence": 1.0, "classifier_rung": "embedding", "objective": "quality", "eliminated": { "vendor-frontier": "residency" }, "chain": ["infra-large"], "chosen": "infra-large" }
A request no model can serve is explained, not refused:
200 with chosen: null
and a refused block naming the constraint.
Explaining is not serving, so it does not adopt serving's 422.
Errors
Refusals are typed and never silent. A spend cap in particular is never a quiet downgrade to something cheaper: the caller cannot tell the difference between "we saved you money" and "your results got worse", so the router refuses instead.
| Status | Type | Means |
|---|---|---|
| 402 | spend_cap_exceeded | The configured cap would be exceeded. Top up, or raise the cap. |
| 422 | no_compliant_candidate | Every candidate was eliminated by a hard filter. The message names which. |
| 502 | all_candidates_failed | The whole fallback chain was exhausted. Each attempt is named. |
Discovery
| Endpoint | Returns |
|---|---|
GET /v1/models | The pool, with each model's residency, tier, context window and capabilities. |
GET /v1/concepts | The catalogue, so you can name a concept explicitly. |
GET /healthz | Liveness. Answers without touching the pool. |
GET /readyz | Readiness: the four artifacts loaded and agreeing with each other. |
Self-hosting
The router is open source and runs as a single container. The four artifacts are config files, validated against each other at startup — a dangling model id is a failed deploy, not a 3am outage.
docker run -p 8080:8080 \
-e ANTHROPIC_API_KEY=... \
-v $PWD/config:/app/config:ro \
ghcr.io/tech-res-group/fiferouter:latest