Loading…
Documentation
Two ways to use the router: the OpenAI-compatible gateway /api/v1 (using an API key from the dashboard) and the simple endpoint /api/ai/chat (anonymous or with a key).
Replace <domain> with your deployment domain, e.g. https://hymn-router.vercel.app
Account
/login with email + password, Google, or GitHub (GitHub is active if the server has its OAuth App configured).Gateway
POST /api/v1/chat/completions, with the OpenAI request/response format. The OpenAI SDK, cURL, and plain fetch all work right away — just change the base URL.Authorization: Bearer hr_... header is required, with an API key from the dashboard. No key / invalid key → 401.model can be hymn/auto (default, full fallback chain), a provider id (e.g. groq), a model id (e.g. openai/gpt-oss-120b), or an OpenRouter model ending in :free (e.g. google/gemma-4-26b-a4b-it:free). Unknown model → 404. The full list (live, may change) is on the /models page.stream: true returns OpenAI-compatible SSE (chunks of choices[0].delta, ending with [DONE]). See the Streaming section below.quota_exceeded). Remaining quota is visible in the dashboard and in the X-Quota-Remaining header.curl <domain>/api/v1/chat/completions \
-H "Authorization: Bearer hr_KEY_ANDA" \
-H "Content-Type: application/json" \
-d '{
"model": "hymn/auto",
"messages": [{ "role": "user", "content": "Halo!" }],
"temperature": 0.7,
"max_tokens": 1024
}'import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HYMN_ROUTER_API_KEY"],
base_url="<domain>/api/v1",
)
res = client.chat.completions.create(
model="hymn/auto", # atau "groq", atau id model
messages=[{"role": "user", "content": "Halo!"}],
)
print(res.choices[0].message.content){
"id": "chatcmpl-9f2ab41c...",
"object": "chat.completion",
"created": 1794569000,
"model": "openai/gpt-oss-120b",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Halo!" },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20 }
}curl <domain>/api/v1/models
# -> { "object": "list", "data": [
# { "id": "hymn/auto", "object": "model", "owned_by": "hymn-router",
# "provider": "hymn-router", "configured": true, "needs_key": false,
# "free_tier": "Fallback chain 9 provider..." },
# { "id": "openai/gpt-oss-120b", "object": "model", "owned_by": "groq",
# "provider": "groq", "configured": true, "needs_key": true,
# "free_tier": "Free: 30 RPM, 1000 req/hari..." },
# ... ] }
# Field tambahan (provider, configured, needs_key, free_tier) aman
# diabaikan client OpenAI. Versi visualnya ada di halaman /models.Real-time
stream: true in the /v1 body (or /api/ai/chat) to receive tokens one by one over Server-Sent Events. The chunk format is the same as OpenAI: text deltas in choices[0].delta.content, the final chunk carries finish_reason, then the line data: [DONE].event: meta with the provider, model, and providers that failed along the way. The /v1 endpoint sends no meta (strictly OpenAI-compatible).curl -N <domain>/api/v1/chat/completions \
-H "Authorization: Bearer hr_KEY_ANDA" \
-H "Content-Type: application/json" \
-d '{
"model": "hymn/auto",
"messages": [{ "role": "user", "content": "Cerita singkat tentang kucing." }],
"stream": true
}'
# -> data: {"id":"chatcmpl-...","object":"chat.completion.chunk",
# "model":"...","choices":[{"index":0,
# "delta":{"role":"assistant","content":""},"finish_reason":null}]}
# -> data: {"id":"...","object":"chat.completion.chunk",
# "choices":[{"index":0,"delta":{"content":"Dulu"},"finish_reason":null}]}
# -> ... (satu chunk per delta teks)
# -> data: {"id":"...","object":"chat.completion.chunk",
# "choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
# -> data: [DONE]from openai import OpenAI
client = OpenAI(api_key="hr_KEY_ANDA", base_url="<domain>/api/v1")
stream = client.chat.completions.create(
model="hymn/auto",
messages=[{"role": "user", "content": "Cerita singkat tentang kucing."}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="", flush=True)Reference
Simple
POST /api/ai/chat calls the 9 free providers (Groq, NVIDIA, Gemini, OpenRouter, Mistral, Kilo, LLM7, Pollinations, OVH) in order until one succeeds.Authorization: Bearer hr_... header: a 60/minute per-key limit, usage recorded in the dashboard, and the 100 requests/day daily quota applies. An invalid Bearer → 401 (no anonymous fallback).stream: true to the body for SSE (same format as /v1, plus an event: meta at the start with the provider/model). The /chat playground uses this mode.curl -X POST <domain>/api/ai/chat \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"halo, jawab singkat"}]}'
# Dengan API key (limit 60/menit/key, tercatat di dasbor):
# -H "Authorization: Bearer hr_KEY_ANDA"{
"messages": [
{ "role": "system", "content": "Jawab singkat." },
{ "role": "user", "content": "Apa itu LLM?" }
],
"temperature": 0.7, // opsional, 0–2, default 0.7
"maxTokens": 1024, // opsional, 1–8192, default 1024
"preferProvider": "groq" // opsional, tetap fallback jika gagal
}{
"provider": "groq",
"model": "openai/gpt-oss-120b",
"content": "LLM adalah ...",
"tried": [], // provider yang gagal sebelum yang berhasil
"usage": {
"prompt_tokens": 18,
"completion_tokens": 42,
"total_tokens": 60
}
}curl <domain>/api/ai/chat
Notes
:free models can disappear or become paid at any time. Check https://openrouter.ai/api/v1/models if a model returns 404.