Wallaby serves open-weight models behind a standard OpenAI-compatible endpoint. If your
code already talks to the OpenAI API, you change two lines — the base_url and the key — and it works here.
POST https://api.wallabytoken.com/v1/chat/completions
sk-.https://api.wallabytoken.com/v1 with your key.Every request carries your API key in the Authorization header:
Authorization: Bearer sk-your-key
Content-Type: application/json
curl https://api.wallabytoken.com/v1/chat/completions \
-H "Authorization: Bearer $WALLABY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3",
"max_tokens": 256,
"messages": [
{"role": "user", "content": "Give me three names for a pet wallaby."}
]
}'
Use the official openai package (pip install openai) with a custom base URL.
from openai import OpenAI
client = OpenAI(
base_url="https://api.wallabytoken.com/v1",
api_key="sk-your-key",
)
resp = client.chat.completions.create(
model="kimi-k3",
max_tokens=256,
messages=[{"role": "user", "content": "Hello!"}],
)
print(resp.choices[0].message.content)
stream = client.chat.completions.create(
model="kimi-k3",
max_tokens=512,
messages=[{"role": "user", "content": "Explain token caching in two sentences."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta and delta.content:
print(delta.content, end="", flush=True)
Kimi K3 is a reasoning model: it thinks before it answers. The thinking arrives in a separate
field, reasoning_content, alongside content — in both streaming deltas and the final non-streaming message.
Render it collapsed, stream it live, or drop it; the answer is always in content.
for chunk in stream:
delta = chunk.choices[0].delta
if not delta:
continue
if getattr(delta, "reasoning_content", None):
# thinking — show it dimmed, or hide it
print(delta.reasoning_content, end="")
if delta.content:
# the actual answer
print(delta.content, end="", flush=True)
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
resp = client.chat.completions.create(
model="kimi-k3",
max_tokens=256,
messages=[{"role": "user", "content": "What's the weather in Sydney?"}],
tools=tools,
)
msg = resp.choices[0].message
if msg.tool_calls:
call = msg.tool_calls[0]
print(call.function.name, call.function.arguments)
# → get_weather {"city": "Sydney"}
Append the tool result as a {"role": "tool", "tool_call_id": ..., "content": ...} message and call again to get the final answer.
Both JSON modes work. json_object guarantees valid JSON; json_schema with strict: true pins the shape.
resp = client.chat.completions.create(
model="kimi-k3",
max_tokens=256,
messages=[{"role": "user",
"content": "List 3 planets with diameter in km and whether they have rings."}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "planet_list",
"strict": True,
"schema": {
"type": "object",
"properties": {
"planets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"diameter_km": {"type": "number"},
"has_rings": {"type": "boolean"},
},
"required": ["name", "diameter_km", "has_rings"],
"additionalProperties": False,
},
}
},
"required": ["planets"],
"additionalProperties": False,
},
},
},
)
print(resp.choices[0].message.content) # guaranteed-schema JSON
| Model | Context | Notes |
|---|---|---|
kimi-k3 | 1M tokens | Open-weight reasoning model. Thinking billed as output. Pricing: price list · machine-readable pricing.json |
The live model list is also queryable:
curl https://api.wallabytoken.com/v1/models \
-H "Authorization: Bearer $WALLABY_API_KEY"
More open-weight models land as we verify them. DeepSeek V4 Flash / Pro are temporarily unavailable while we reprice against the new official list.
| Parameter | Status | Behaviour |
|---|---|---|
model | ✓ required | kimi-k3 |
messages | ✓ required | Standard chat roles: system / user / assistant / tool |
stream | ✓ | SSE. Deltas carry reasoning_content then content; final chunk includes usage |
max_tokens / max_completion_tokens | ✓ | Both aliases accepted. Caps generated tokens; thinking counts toward output |
stop | ✓ | String or array of stop sequences |
seed | ✓ accepted | Passed through; best-effort determinism, not guaranteed |
tools / tool_choice | ✓ | Function calling — see tool use |
response_format | ✓ | json_object and json_schema (strict) — see structured outputs |
temperature | normalised | Any value accepted. Requests are served at 1 (upstream model constraint); the value is normalised automatically |
top_p | normalised | Any value accepted; served at 0.95 (upstream constraint) |
presence_penalty / frequency_penalty | normalised | Any value accepted; served at 0 (upstream constraint) |
n | normalised | Single completion only; values > 1 are normalised to 1 |
| HTTP | Meaning | What to do |
|---|---|---|
400 | Invalid request body | Check JSON shape against this page; the message field names the offending parameter |
401 | Invalid token — key missing, wrong, or revoked | Verify the Authorization: Bearer header; issue a new key in the console |
403 | Key has no access to that model, or balance is exhausted (insufficient_user_quota) | Check the key's model scope; top up in the console |
429 | Rate limited, or upstream briefly saturated | Back off with jitter and retry; persistent 429s — email us |
5xx | Gateway or upstream fault | Retry with exponential backoff; check status.wallabytoken.com for live incidents |
Errors follow the OpenAI shape: {"error": {"message": "...", "type": "...", "code": ...}}, with a request id in the message — quote it when contacting support.
Usage-reporting API endpoints are on the roadmap. Today the console is the source of truth.