Documentation
Linka API docs
Everything you need to call every major LLM through one OpenAI-compatible endpoint: https://api.linka.ink/v1.
Quickstart
Linka speaks the OpenAI chat-completions protocol, so if you have working OpenAI code you are one base-URL change away from every model on the platform.
- Create an account and API key. Sign in to the Linka console at app.linka.ink, top up your balance (any amount from $10), and generate a key. Keys begin with
sk-linka-. - Point your client at Linka. The base URL is
https://api.linka.ink/v1. - Make your first request. Pick any model ID from the models page and send a chat completion:
curl "https://api.linka.ink/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-linka-your-key" \
-d '{
"model": "openai/gpt-4o",
"messages": [
{ "role": "user", "content": "Hello from Linka!" }
]
}'from openai import OpenAI
client = OpenAI(
api_key="sk-linka-your-key",
base_url="https://api.linka.ink/v1",
)
resp = client.chat.completions.create(
model="anthropic/claude-sonnet-4.5",
messages=[{"role": "user", "content": "Hello from Linka!"}],
)
print(resp.choices[0].message.content)
print(resp.usage) # prompt_tokens, completion_tokens, cost_creditsimport OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-linka-your-key",
baseURL: "https://api.linka.ink/v1",
});
const resp = await client.chat.completions.create({
model: "google/gemini-2.5-flash",
messages: [{ role: "user", content: "Hello from Linka!" }],
});
console.log(resp.choices[0].message.content);That is the whole integration. Change only the model string to route the same request to any other provider on the platform.
Authentication
Every request must carry your API key as a Bearer token in the Authorization header:
Authorization: Bearer sk-linka-your-key- Keys are shown once at creation. Store them like passwords.
- Create separate keys per environment or service, with per-key spend caps, in the console.
- If a key leaks, revoke it in the console immediately — revocation is instant — then email support@linka.ink if you see usage you do not recognize.
Endpoints
| Endpoint | Description |
|---|---|
| POST /v1/chat/completions | Create a chat completion. Supports streaming, tool calling, JSON mode, and fallback chains. |
| GET /v1/models | List available models with context lengths and current per-token pricing. |
| GET /v1/credits/balance | Return your current prepaid credit balance and lifetime totals. |
curl "https://api.linka.ink/v1/models" \
-H "Authorization: Bearer sk-linka-your-key"
# {
# "object": "list",
# "data": [
# {
# "id": "openai/gpt-4o",
# "object": "model",
# "context_length": 128000,
# "pricing": { "prompt": 2.50, "completion": 10.00 }
# },
# ...
# ]
# }curl "https://api.linka.ink/v1/credits/balance" \
-H "Authorization: Bearer sk-linka-your-key"
# {
# "balance": 48.21,
# "currency": "USD",
# "lifetime_topups": 60.00,
# "lifetime_usage": 11.79
# }Routing & fallbacks
Model IDs use the provider/name format, e.g. anthropic/claude-sonnet-4.5. For production workloads, pass a models array instead of a single model to define an ordered fallback chain:
{
"models": [
"anthropic/claude-sonnet-4.5",
"openai/gpt-4o",
"google/gemini-2.5-pro"
],
"messages": [ { "role": "user", "content": "Summarize this ticket." } ]
}Linka tries each model in order and returns the first successful response. The model that actually served the request is always in the response's model field, and you are billed at that model's rate. Failover across providers typically adds one round-trip of latency.
Streaming
Set "stream": true to receive server-sent events. The stream emits chat.completion.chunk objects and terminates with data: [DONE]. Streamed requests are billed exactly like non-streamed requests once the stream completes.
curl "https://api.linka.ink/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-linka-your-key" \
-d '{
"model": "deepseek/deepseek-chat-v3",
"stream": true,
"messages": [ { "role": "user", "content": "Count to five." } ]
}'
# data: {"id":"chatcmpl-linka-...","choices":[{"delta":{"content":"1"}}]}
# data: {"id":"chatcmpl-linka-...","choices":[{"delta":{"content":", 2"}}]}
# ...
# data: [DONE]Error codes
Errors return a non-2xx status and a JSON body with a machine-readable type:
{
"error": {
"message": "Insufficient credits. Top up your balance to continue.",
"type": "insufficient_credits",
"code": 402
}
}| Code | Type | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request | The request body is malformed or a parameter is invalid. | Check the JSON body and parameter names against this documentation. |
| 401 | authentication_error | Missing or invalid API key. | Send Authorization: Bearer sk-linka-... with an active key. |
| 402 | insufficient_credits | Your prepaid balance is too low to serve the request. | Top up in the console; the request is not served and nothing is billed. |
| 404 | not_found | Unknown model ID or endpoint. | Check the model ID on the models page or via GET /v1/models. |
| 429 | rate_limited | Too many requests for your key. | Back off and honor the Retry-After header. |
| 500 | internal_error | Something went wrong on Linka's side. | Retry with exponential backoff; contact support if it persists. |
| 502 | upstream_error | The upstream provider returned an error. | Retry, or configure a fallback model chain. |
| 503 | upstream_unavailable | The upstream provider is temporarily unavailable. | Retry shortly; fallback chains reroute automatically. |
Rate limits
Default limits are 600 requests per minute and 60 concurrent requests per API key, across all models. Exceeding either returns 429 with a Retry-After header.
Need more? We routinely raise limits for funded accounts — email support@linka.ink with your expected throughput.
Billing notes
- Every response includes a
usageobject withprompt_tokens,completion_tokens, andcost_credits— the exact amount deducted for that call. - Requests that fail with a 4xx error are never billed. Upstream 5xx failures are refunded automatically to your balance.
- When your balance cannot cover a request, the API returns
402 insufficient_creditsand nothing is served or charged. - Credits never expire. Unused credits are refundable within 14 days of top-up — see the refund policy.