Bhaskara Labs

Documentation

API documentation

Two drop-in endpoint families, three model names, and one set of caching rules. If it speaks OpenAI or Anthropic, it speaks to us after a base URL and a key.

Base URL
https://api.bhaskaralabs.com
Auth
Bearer · x-api-key

01 Quick start

Three steps to a working request.

  1. 01

    Get a key

    Sign in with GitHub, open the dashboard, and create one. It is shown once and stored hashed; revoke it from the same screen.

  2. 02

    Point one environment variable

    Every mainstream agent accepts a custom OpenAI- or Anthropic-compatible base URL.

    environment
    BHASKARA_API_KEY="sk-bhaskara-…"
    BHASKARA_BASE_URL="https://api.bhaskaralabs.com/v1"
  3. 03

    Send a request

    curl
    curl -s $BHASKARA_BASE_URL/chat/completions \
      -H "Authorization: Bearer $BHASKARA_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "theta",
        "messages": [{ "role": "user", "content": "Rust borrow checker, one paragraph." }]
      }'

02 Model names

You name a family, never a substituted one.

NameWhat answers, and how it is metered
glm-5.3The GLM-5.3 family on a one-million-token context. A capability-and-cost objective picks the full or flash variant per turn and holds it for the session, so the provider cache stays warm. The full model is capped at a quarter of your glm calls. Metered per request, with a token budget on the same window.
thetaOur own model, on a 200K context. Built and served by us end to end: the inference stack, the routing between its backends and the tuning are ours. Metered per request in a rolling five-hour window, so the price does not move with the prompt.

03 Endpoints

Two shapes, both drop-in.

POST /v1/chat/completions

OpenAI-compatible. Accepts messages, stream, temperature, max_tokens and standard tool calling. Streaming follows the OpenAI SSE shape: data: chunks, a terminating [DONE], and usage in the final chunk when requested.

curl
curl -s $BHASKARA_BASE_URL/chat/completions \
  -H "Authorization: Bearer $BHASKARA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"glm-5.3","messages":[{"role":"user","content":"explain cache-aware prompt prefixes"}]}'

POST /v1/messages

Anthropic-compatible: system, messages[] with content blocks, anthropic-version and x-api-key auth. The SSE event shapes are the ones Claude Code already parses: message_start, content_block_delta, message_stop.

Any OpenAI or Anthropic SDK, unchanged

The only two values that change are the base URL and the key.

python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.bhaskaralabs.com/v1",
    api_key="sk-bhaskara-…",
)
r = client.chat.completions.create(
    model="theta",
    messages=[{"role": "user", "content": "fix my SQL window fn"}],
)
print(r.choices[0].message.content)
typescript
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic({
  baseURL: "https://api.bhaskaralabs.com",
  apiKey: process.env.BHASKARA_API_KEY,
});

const msg = await anthropic.messages.create({
  model: "glm-5.3",
  max_tokens: 1024,
  messages: [{ role: "user", content: "review this diff" }],
});

04 Integrations

Base URL, key, model name. That is the whole contract.

Claude Code

Uses the /v1/messages path natively, and sub-agents inherit the base URL.

claude code
ANTHROPIC_BASE_URL=https://api.bhaskaralabs.com \
ANTHROPIC_AUTH_TOKEN=$BHASKARA_API_KEY \
claude --model glm-5.3

Codex CLI

~/.codex/config.toml

codex cli
model = "glm-5.3"
model_provider = "bhaskara"

[model_providers.bhaskara]
name = "Bhaskara Labs"
base_url = "https://api.bhaskaralabs.com/v1"
env_key = "BHASKARA_API_KEY"
wire_api = "chat"

openCode

opencode.json

opencode
{
  "provider": {
    "bhaskara": {
      "npm": "@ai-sdk/openai-compatible",
      "options": {
        "baseURL": "https://api.bhaskaralabs.com/v1",
        "apiKey": "{env:BHASKARA_API_KEY}"
      },
      "models": {
        "glm-5.3": { "name": "GLM-5.3 (routed)" },
        "theta": { "name": "Theta" }
      }
    }
  },
  "model": "bhaskara/glm-5.3"
}

Crush

Crush's provider config takes an OpenAI-compatible override — the same three values. If you already point it at another provider, change the base URL and swap the key.

crush
# the same three values as everywhere else
BHASKARA_BASE_URL="https://api.bhaskaralabs.com/v1"
BHASKARA_API_KEY="sk-bhaskara-…"

pi / omp

Both accept custom OpenAI-compatible providers in their model config. Add bhaskara with the base URL above and the three model names, with the key supplied through the environment.

pi / omp
BHASKARA_BASE_URL="https://api.bhaskaralabs.com/v1"
BHASKARA_API_KEY="sk-bhaskara-…"

05 Caching rules

Four rules decide what your session costs.

  1. 01

    Stable prefix first

    Cache reads are computed on the request prefix, so order it: system prompt, then tool definitions, then long-lived context, then your varying turns. A byte-identical prefix is billed at the cache rate; one edit mid-context invalidates everything after it.

  2. 02

    Append only

    Do not rewrite history and do not prune the middle. Trim from the front at a safe boundary, or do not trim at all.

  3. 03

    Keep the family stable across a session

    Our router locks a session to the variant chosen on its first request, with a two-hour idle TTL. Flipping variants mid-session wipes the provider cache and re-bills the whole prefix, so we do not do it. One priced exception exists: a genuinely hard turn in a flash-locked session can upgrade once to the full model, and only while the cache-wipe penalty stays under budget and your weekly full-model share has headroom. Downgrades never happen mid-session.

  4. 04

    Watch the headers, not your intuition

    x-ratelimit-remaining-* and the cache column in your dashboard report the real hit rate. If it is low, the prefix ordering is the problem, not the pipe.

06 Quotas & errors

Every response carries your live quota state.

HeaderMeaning
x-quota-plantrial, starter or pro.
x-quota-monthly-resetISO date the token quotas roll over.
x-ratelimit-*-tokensFrontier: the monthly token dimension, with reset in seconds.
x-ratelimit-*-requeststheta: the rolling five-hour window.
x-quota-output-tokens-remainingFrontier monthly output remainder.
Retry-AfterOn 429 only — seconds until the window or month resets.
401Bad or revoked key.
400Unknown model name. The allowed three are listed above.
429Quota exhausted, with Retry-After. Never a silent degrade.
502Upstream failure. Retryable; our error body never names providers.

07 Streaming

Long generations stay connected.

"stream": true on /v1/chat/completions gives OpenAI-style SSE. On /v1/messages it gives Anthropic event types. Tool-call deltas stream in the same shape the native APIs use, so agent harnesses parse them without an adapter.

The gateway runs on infrastructure without a platform request timeout, precisely so a frontier generation with long reasoning is not cut off mid-stream.

08 Terse mode

Output compression, on request and off by default.

Send x-bhaskara-terse: 1 on either endpoint and replies come back as compressed engineer-speak: no preamble, no restatement, no closing summary. Code, commands and file paths stay byte-exact. Safety-relevant replies are exempted by instruction.

curl
curl -s $BHASKARA_BASE_URL/chat/completions \
  -H "Authorization: Bearer $BHASKARA_API_KEY" \
  -H "x-bhaskara-terse: 1" \
  -H "Content-Type: application/json" \
  -d '{"model":"glm-5.3","messages":[…]}'

09 Parallel projects

One key, many projects — give each a session.

Sessions derive from your key by default, which is right for one project. Run several against the same key and they would share a session lock and fight over one provider cache. Send x-bhaskara-session with a stable value per project — the repo or folder name is enough — and each gets its own routing lock, cache line and compaction window.

per project
# project A
export BHASKARA_SESSION="api-redesign"

curl -s $BHASKARA_BASE_URL/chat/completions \
  -H "Authorization: Bearer $BHASKARA_API_KEY" \
  -H "x-bhaskara-session: $BHASKARA_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"model":"glm-5.3","messages":[…]}'

In agent CLIs, set it once as an environment variable or in the same config block as the base URL — the header rides on every request of the session. Keep the value byte-stable for the life of the project; a new value is a new session, with a cold cache.

ValueBehaviour
x-bhaskara-session: my-projectRouting lock, cache line and compaction are scoped to this key + value pair.
(not sent)Session defaults to the key itself — correct for single-project use.

Stuck? The FAQ covers quotas and billing, and the calculator covers the arithmetic.