API reference

Base URL https://api.altworld.io/v1. Every request carries Authorization: Bearer aw_live_…. Errors use the OpenAI envelope: {"error": {"message", "type", "code"}}. CORS is open, so browser apps work — but never ship your key to the client.

POST /v1/chat/completions

One endpoint, streaming and non-streaming. The request body is built from the fields below; anything else is ignored.

FieldTypeDefaultNotes
modelstringrequired; astrea (aliases: astrea-1, altworld/astrea)
messagesarrayrequired; ≤64 entries, string content only, ≤32k chars each, ≤100k total. Leading system folds into the first user turn; system later → 400. Consecutive same-role turns merge. Last message must be user.
streamboolfalseSSE when true
max_tokensint700≤4,096
temperaturenumber0.80 – 1.5 · use ~0.2 for factual chat
min_pnumber0.0250 – 0.5
repetition_penaltynumber1.081 – 1.5
top_pnumber10.05 – 1
presence_penaltynumber0−2 – 2
frequency_penaltynumber0−2 – 2
stopstring | array≤4 strings, ≤32 chars each
seedintbest-effort determinism
stream_optionsobject{"include_usage": true} adds a final usage chunk

The defaults are the release-verified sampling settings — the exact configuration Astrea's published benchmark numbers were measured at.

Non-streaming response

{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "model": "astrea",
  "choices": [{
    "index": 0,
    "message": { "role": "assistant", "content": "…" },
    "finish_reason": "stop"
  }],
  "usage": { "prompt_tokens": 42, "completion_tokens": 512, "total_tokens": 554 }
}

Streaming

Server-sent events; each event is a data: line holding a chat.completion.chunk with choices[0].delta.content. The stream ends with data: [DONE]. If you set stream_options.include_usage, one final chunk before [DONE] carries usage and an empty choices array.

data: {"object":"chat.completion.chunk","model":"astrea","choices":[{"delta":{"content":"The"}}]}

data: {"object":"chat.completion.chunk","model":"astrea","choices":[{"delta":{"content":" tide"}}]}

data: [DONE]

GET /v1/models

The model list — one entry, astrea, with context_window metadata.

GET /v1/me

Your key, credit balance, usage today (UTC), and current pricing. Use it to build dashboards or alert on a low balance.

{
  "key": { "id": "…", "name": "my-app" },
  "balance_usd": 4.9832,
  "rate_limit": { "requests_per_minute": 60, "max_tokens_per_request": 4096 },
  "usage_today": { "day_utc": "20260720", "requests": 12, "input_tokens": 8123, "output_tokens": 20411 },
  "pricing": { "input_per_million": 0.20, "output_per_million": 0.80, "currency": "USD" },
  "manage": "https://altworld.io/developer"
}

Billing & rate limits

Prepaid credits. Load your balance by card at altworld.io/developer ($5 minimum; credits never expire). Each request debits exactly what it used — $0.20 per 1M input tokens, $0.80 per 1M output. At zero balance requests return 402 insufficient_credits; a request already in flight can dip the balance slightly negative, and that settles on your next top-up.

Every key is limited to 60 requests/min (need more? email astrea@altworld.io). Responses carry x-ratelimit-limit-requests, x-ratelimit-remaining-requests, and x-astrea-balance-usd, plus an x-request-id to quote in bug reports.

Errors

StatusCodeMeaning
400invalid body, parameter out of bounds, misplaced system message
401missing_api_key / invalid_api_keyno key, unknown key, or revoked key
402insufficient_creditsbalance empty — top up at altworld.io/developer
404model_not_foundmodel isn't astrea
413body over 512 KB
429rate_limit_exceededper-minute limit; honor retry-after
502 / 503upstream_*the model is waking from scale-to-zero or at capacity — retry with backoff

Cold starts are real: after a quiet period the first request can take noticeably longer while the model wakes. Set generous client timeouts (60 s+) and retry 502/503 with backoff.

Privacy

The gateway never logs or stores message content — request ids, token counts, and latency only. Prompts are processed to generate the completion and discarded.