SporeLabs API Reference

SporeLabs is an OpenAI-compatible inference endpoint. Change your base_url and api_key, keep your existing client.

Base URL:  https://sporelabs.dev/v1
Auth:      Authorization: Bearer <api-key>

If you already have code that calls OpenAI, swap two lines and everything keeps working:

# Before
client = OpenAI(api_key="sk-...")

# After
client = OpenAI(
    base_url="https://sporelabs.dev/v1",
    api_key="sl-xxx...",
)

Request/response shapes, auth headers, SSE streaming format, tool calls, JSON mode, and error envelopes all follow the OpenAI API contract. What is different:

  1. Model IDs use OpenRouter's provider/model format (or omit model entirely — see Model IDs).
  2. Base URL is https://sporelabs.dev/v1 (not https://api.openai.com/v1).
  3. Payment is a prepaid dollar wallet debited at real upstream spend (pass-through, no markup), not postpaid billing.
  4. Extra endpoints like /v1/improve/settings are SporeLabs-only additions beyond the OpenAI spec.

Quick Start (copy-paste)

Python (openai SDK)

from openai import OpenAI

client = OpenAI(
    base_url="https://sporelabs.dev/v1",
    api_key="sl-xxx...",
)

response = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

Omit model (or send "auto") to let SporeLabs pick: traffic starts on Kimi K3 (moonshotai/kimi-k3) and only moves when a cheaper model is proven equal on your traffic.

curl

curl https://sporelabs.dev/v1/chat/completions \
  -H "Authorization: Bearer sl-xxx..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

JavaScript (openai npm)

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://sporelabs.dev/v1",
  apiKey: "sl-xxx...",
});

const response = await client.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);

Anthropic SDK

The Anthropic surface (/v1/messages) is served from the same base URL — use x-api-key or Bearer with your SporeLabs key:

import anthropic

client = anthropic.Anthropic(
    base_url="https://sporelabs.dev/v1",
    api_key="sl-xxx...",
)

message = client.messages.create(
    model="anthropic/claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)
print(message.content[0].text)

Streaming (SSE)

stream = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Count to 5"}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

OpenAI-Compatible Endpoints

These endpoints match the OpenAI API shape so any OpenAI SDK works with a base URL swap.

POST /v1/chat/completions

Create a chat completion.

Request body (OpenAI ChatCompletionRequest):

Field Type Required Notes
model string no OpenRouter slug like openai/gpt-4o, or omit / "auto" to let SporeLabs route (starts on Kimi K3). See Model IDs.
messages array yes Standard OpenAI message array. Roles: system, user, assistant, tool.
stream boolean no Enable SSE streaming (default false).
temperature number no Sampling temperature (0-2, default varies by model).
max_tokens integer no Maximum tokens in response.
tools array no Function/tool definitions. Supported.
tool_choice string/object no "auto", "any", "none", or {"type":"function","function":{"name":"..."}}.
response_format object no {"type": "json_object"} for JSON mode.
stop string/array no Stop sequences.
seed integer no Deterministic sampling (best-effort).
frequency_penalty number no -2 to 2.
presence_penalty number no -2 to 2.
top_p number no Nucleus sampling (0-1).
user string no End-user identifier for usage tracking.

Response (OpenAI ChatCompletion):

{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1698850000,
  "model": "openai/gpt-4o",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help you?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 7,
    "total_tokens": 19
  }
}

When stream=true, each chunk follows the OpenAI SSE format:

data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":1698850000,"model":"openai/gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]

GET /v1/models

List available models: a minimal set — auto, the Kimi incumbent, and owned adapters — not the full OpenRouter index.

Response:

{
  "object": "list",
  "data": [
    {
      "id": "openai/gpt-4o",
      "object": "model",
      "created": 1698850000,
      "owned_by": "openai"
    }
  ]
}

GET /v1/models/{model_id}

Retrieve a specific model by its OpenRouter slug.


SporeLabs-Specific Endpoints

These are not part of the OpenAI standard but use the same base URL and bearer token. Full details in the Jobs API doc.

Method Path Description
POST /v1/improve/settings Save improvement routing/specialization settings.
POST /v1/specializations/{spec_id}/apply Apply a specialization pattern.
GET /v1/agent-proposals List hosted agent proposals.
POST /v1/agent/codes Generate an invite code for an agent session.
POST /v1/agent/token Exchange invite code for a short-lived agent token.
GET /v1/jobs List training/inference jobs (read-only support endpoint).
GET /v1/jobs/{job_id} Get details for one job (read-only support endpoint).
Various /v1/datasets Import, export, delete datasets.

Authentication

All endpoints use standard bearer authentication:

Authorization: Bearer <api-key>

Get your API key from the SporeLabs portal dashboard.


Errors

Errors follow the OpenAI error envelope:

{
  "error": {
    "message": "Insufficient funds",
    "type": "insufficient_quota",
    "param": null,
    "code": "insufficient_quota"
  }
}

Common error types:

HTTP Status Type Meaning
400 invalid_request_error Malformed request body. On the Anthropic surface (/v1/messages), an empty wallet also returns 400.
401 authentication_error Missing or invalid API key.
404 invalid_request_error Unknown model or endpoint.
429 insufficient_quota Wallet is empty — top up in the portal. Also used for rate limiting. 402 is never returned on SDK paths.
503 upstream_unavailable / api_error Upstream provider blip; retry with backoff.
500 api_error Server error; retry with backoff.

Model IDs

Omit model (or send auto) and SporeLabs routes for you: Auto starts on Kimi K3 (moonshotai/kimi-k3) and moves a job to a cheaper model only after proving equality on your traffic. Name a model and that exact model serves the call.

Named models use OpenRouter slugs. Common ones:

moonshotai/kimi-k3
openai/gpt-4o
openai/gpt-4o-mini
openai/o3-mini
anthropic/claude-sonnet-4-20250514
anthropic/claude-3.5-haiku-20241022
google/gemini-2.5-pro-preview-03-25
meta-llama/llama-3.3-70b-instruct

Get the current list from GET /v1/models.


Limits