Documentation

Quickstart, providers, modes, encryption internals, and the API reference, everything to get the most out of sarmalink.

Quickstart

Get from zero to your first answer in under two minutes. Sign in with a magic link, create your encryption passphrase, and paste a single free-tier provider key.

  1. 1Sign in with your email, no password to remember.
  2. 2Create a passphrase. It encrypts everything locally.
  3. 3Add one free key — any provider unlocks every mode it can serve.
  4. 4Start chatting. Add more keys anytime in Settings.

Providers

sarmalink routes across 17 OpenAI-compatible providers. Each has a generous free tier. Any single key enables every mode its provider can serve; extra keys deepen the failover ladder.

ProviderFree tier
Groq14,400 requests/day, 30 RPM
SambaNovaFrontier model, generous daily quota
Cerebras1M tokens/day free
Google GeminiFlash + Pro, Search grounding
OpenRouter17+ models, free variants
NVIDIA NIM1000 free credits at sign-up
DeepSeekPay-as-you-go, very cheap
Alibaba QwenFree tier on DashScope
Moonshot KimiFree trial credits
Zhipu GLMGenerous free quota
MistralLa Plateforme free tier
OpenAIPaid — usage-based
AnthropicPaid — usage-based
xAI GrokPaid — usage-based
Together AIFree endpoints on select open models
Fireworks AIPaid — usage-based
Novita AIFree trial credits

Modes

A mode is a curated engine + behaviour. Pick one per message; the gateway selects the best available provider and fails over silently.

Smart

DeepSeek V3.2 685B MoE

Professional emails, deep analysis, long-form reasoning.

Reasoner

DeepSeek R1

Chain-of-thought made visible for GDPR-shaped questions.

Live

Gemini 2.5 Flash

Fast, broad-knowledge answers from Google’s Flash model.

Fast

Groq GPT-OSS 20B

41ms first token, built for quick lookups.

Coder

DeepSeek V3.2 + Qwen 3 Coder

Debug, refactor, and write tests with a code-tuned engine.

Vision

Llama-4 Scout

Llama-4 Scout via Groq. Image upload is on the roadmap.

Encryption

Your passphrase derives a vault key with PBKDF2 (600,000 iterations, above OWASP 2024 guidance). Provider keys and messages are sealed with AES-256-GCM in the browser.

WebCrypto
const key = await crypto.subtle.deriveKey(
  { name: 'PBKDF2', salt, iterations: 600_000, hash: 'SHA-256' },
  passphraseKey,
  { name: 'AES-GCM', length: 256 },
  false,
  ['encrypt', 'decrypt'],
)

API reference

Send a chat completion through the gateway. Specify a mode and the gateway picks the provider.

HTTP
POST /api/chat
Authorization: Bearer <session-token>
Content-Type: application/json

{
  "mode": "smart",
  "messages": [
    { "role": "user", "content": "Summarise this contract clause" }
  ]
}

Personal endpoint

sarmalink also exposes an OpenAI-compatible relay at/api/v1so Claude Code, Cursor, VS Code Continue, OpenAI client libs, and any tool that speaks the OpenAI shape can use your keys through one base URL. Authenticate with your Supabase access token (see Settings → Personal API for the live one).

List models

HTTP
GET https://ai.sarmalinux.com/api/v1/models
Authorization: Bearer $SARMALINK_TOKEN

→ 200 { object: "list", data: [{ id: "groq/default", ... }, ...] }

Chat completion

Provider routing follows the failover order for the requested mode and skips providers you have no remote key for.

HTTP
POST https://ai.sarmalinux.com/api/v1/chat/completions
Authorization: Bearer $SARMALINK_TOKEN
Content-Type: application/json

{
  "model": "groq/default",
  "mode": "smart",
  "messages": [{ "role": "user", "content": "Hello from Cursor" }],
  "stream": true
}

Response: standard text/event-stream forwarded directly from the upstream provider. TheX-Sarmalink-Providerheader tells you which provider answered.

Manage remote keys

HTTP
# List
GET /api/v1/keys
→ { keys: [{ provider, enabled, created_at }, ...], server_ready: boolean }

# Add / replace
POST /api/v1/keys
{ "provider": "deepseek", "key": "sk-…" }

# Remove
DELETE /api/v1/keys?provider=deepseek

Use sarmalink from coding toolsBeta

The personal endpoint speaks the OpenAI wire format, so any OpenAI SDK or OpenAI-compatible client can point at it. Three things to configure:

  • Base URL: https://ai.sarmalinux.com/api/v1
  • API key: your personal token from Settings → Personal API, sent as Authorization: Bearer <token> (exactly what every OpenAI SDK does with its apiKey field)
  • Model: any id from GET /api/v1/models, e.g. groq/default

How the model parameter behaves: the segment before the slash names the provider sarmalink tries first; the relay then falls back through the failover order for the requested mode (smart, reasoner, live, fast, coder, vision; default smart), skipping providers you have not enabled. Each provider serves its curated model for that mode, and responses are always streamed as server-sent events. Only providers you have enabled under Settings → Personal API are used.

curl

Shell
curl https://ai.sarmalinux.com/api/v1/chat/completions \
  -H "Authorization: Bearer $SARMALINK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "groq/default",
    "messages": [{ "role": "user", "content": "Hello from curl" }]
  }'

OpenAI JS SDK

TypeScript
import OpenAI from 'openai'

const client = new OpenAI({
  baseURL: 'https://ai.sarmalinux.com/api/v1',
  apiKey: process.env.SARMALINK_TOKEN,
})

const stream = await client.chat.completions.create({
  model: 'groq/default',
  messages: [{ role: 'user', content: 'Hello from my editor' }],
  stream: true,
})

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? '')
}

OpenAI Python SDK

Python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://ai.sarmalinux.com/api/v1",
    api_key=os.environ["SARMALINK_TOKEN"],
)

stream = client.chat.completions.create(
    model="groq/default",
    messages=[{"role": "user", "content": "Hello from Python"}],
    stream=True,
)

for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

Continue / Cline-style config

Any editor extension with an “OpenAI-compatible” provider option works the same way — set the base URL, paste the token as the API key, pick a model id.

JSON
{
  "models": [
    {
      "title": "sarmalink",
      "provider": "openai",
      "apiBase": "https://ai.sarmalinux.com/api/v1",
      "apiKey": "<token from Settings → Personal API>",
      "model": "groq/default"
    }
  ]
}

Claude Code (Anthropic-format endpoint)

sarmalink also speaks the Anthropic Messages format at /api/v1/messages, so Claude Code and any tool built on the Anthropic SDK can use your keys too. The Anthropic SDK appends /v1/messages to its base URL itself, so the base URL ends at /api — not /api/v1:

Shell
export ANTHROPIC_BASE_URL="https://ai.sarmalinux.com/api"
export ANTHROPIC_API_KEY="<token from Settings → Personal API>"
claude
  • Model mapping: any claude-* model id (what Claude Code sends by default) maps to your failover-ladder default, so no model config is needed. To pin a provider first, set ANTHROPIC_MODEL to a provider-prefixed id like groq/default — same semantics as the OpenAI endpoint.
  • Auth: both x-api-key (what the Anthropic SDK sends) and Authorization: Bearer are accepted; the anthropic-version header is accepted and ignored.
  • Beta, text-only: image blocks are rejected with a clear error and tool calls are not relayed, so agentic tool use degrades to plain chat. Token counts in usage are estimates (chars ÷ 4), and the same Settings → Personal API remote-key setup applies. The X-Sarmalink-Provider response header names the provider that answered.

Beta caveats: the endpoint relays through server-side remote keys, so enable at least one provider under Settings → Personal API first (you will get 400 no_remote_keys otherwise, or 501 remote_keys_unconfigured if the deployment has remote keys switched off). Tokens are session-bound and expire — refresh from Settings if you see 401 invalid_bearer. Long-lived personal access tokens are on the roadmap.

Error shapes

Every JSON error follows the OpenAI shape so your existing SDK error handling keeps working.

JSON
{
  "error": {
    "type": "invalid_request_error",
    "code": "missing_bearer",
    "message": "Missing bearer token"
  }
}
  • 401 missing_bearer · no Authorization header.
  • 401 invalid_bearer · token expired or wrong project.
  • 400 no_remote_keys · enable at least one provider in Settings → Personal API first.
  • 501 remote_keys_unconfigured · server is missing the master key env.
  • 502 all_providers_failed · every enabled provider returned an error; check your keys.