Overview
The Adapter API is a stateless, OpenAI Chat Completions-compatible inference API served on your own dedicated GPU capacity. You use the standard OpenAI SDK — only the base URL, key, and model change.
Two things differ from a hosted model like GPT-4:
- You control when the model is active. Activating loads it onto a dedicated GPU on demand — real cost — so you turn it on and off.
- The "model" is your own trained adapter, pinned to a specific version.
You create the API key and endpoint in the dashboard's Developer section; this guide covers using them from code.
Quickstart
Activate the endpoint, wait until it's live, call it, then release the GPU:
import time, requests
from openai import OpenAI
BASE_URL = "https://api.thesuperposition.ai/v1"
API_KEY = "tsk_your_key_here"
ENDPOINT = "your_endpoint_id"
auth = {"Authorization": f"Bearer {API_KEY}"}
# 1. Activate (add ?ttlMinutes=60 to auto-deactivate after an hour)
requests.post(f"{BASE_URL}/endpoints/{ENDPOINT}/activate", headers=auth)
# 2. Poll until live (startup ~1-3 min; poll no faster than ~5s)
while not requests.get(f"{BASE_URL}/endpoints/{ENDPOINT}/status", headers=auth).json()["live"]:
time.sleep(5)
# 3. Infer with the standard OpenAI SDK
client = OpenAI(base_url=BASE_URL, api_key=API_KEY)
resp = client.chat.completions.create(
model=ENDPOINT,
messages=[{"role": "user", "content": "Introduce yourself."}],
)
print(resp.choices[0].message.content)
# 4. Release the GPU when done
requests.post(f"{BASE_URL}/endpoints/{ENDPOINT}/deactivate", headers=auth)
Concepts
| Term | Meaning |
|---|---|
| Endpoint | The addressable model you call. It pins one specific trained adapter version and is named by an endpoint id, which you pass as the OpenAI model field. |
| API key | Your secret (tsk_…). Authenticates every inference and activation call. Shown once when created; store it securely. Sent as a Bearer token. |
| Active / live | An endpoint must be live (loaded on a dedicated GPU and serving) before it answers. Activating it takes ~1–3 min to reach live (startup). You control activation explicitly. |
| Stateless | No conversation memory is kept. Send the full message history on every call, exactly like the OpenAI API. |
Authentication
Every request carries your API key as a Bearer token:
Authorization: Bearer tsk_your_key_here
(An X-API-Key: tsk_… header is also accepted.) A missing, invalid, expired, or revoked key returns 401:
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key", "message": "Invalid or missing API key." } }
Request lifecycle
1. Activate POST /v1/endpoints/{id}/activate → GPU starts loading
2. Wait live GET /v1/endpoints/{id}/status (poll) → until { "live": true }
3. Infer POST /v1/chat/completions → completions (stream or not)
4. (optional) POST /v1/endpoints/{id}/deactivate → release the GPU
409 endpoint_not_live and does nothing else —
activation is always the separate step 1. Activate ahead of
traffic; don't try to trigger activation by sending a chat call.
Managing activation
All activation calls use your API key. There are three ways an endpoint becomes active.
Manual — active until you stop it
POST /v1/endpoints/{id}/activate
→ 200 { "status": "warming" } // or "ready" if it was already live
Stays active until you deactivate, bounded by a 24h safety cap (re-activate to extend).
TTL — active for a fixed duration
POST /v1/endpoints/{id}/activate?ttlMinutes=60
→ 200 { "status": "warming" }
Auto-deactivates after ttlMinutes (clamped 1–1440). No need to remember to deactivate.
Scheduled — recurring windows
Scheduled activation (e.g. "active 8–11am Mon–Fri") is configured by
the account owner in the dashboard, not through this API. The server
activates a few minutes before each window opens and deactivates at the end —
no per-window call from your app. Your app just checks status and infers.
Deactivate
POST /v1/endpoints/{id}/deactivate
→ 200 { "status": "deactivated" }
Status (poll this)
GET /v1/endpoints/{id}/status
→ 200 {
"active": true, // activation is turned on
"live": true, // ready to serve inference RIGHT NOW
"warm_until": "2026-07-16T20:00:00Z" // when activation expires (user-facing)
}
- Gate your inference on
live. Afteractivate, poll untillive: true(startup ~1–3 min), then send chat calls. - Poll no faster than ~5s — readiness refreshes on a ~20s server cadence, so tighter polling only adds load.
- Show
warm_untilas the human "active until" time. (ready_untilmay also appear; it's an internal lease horizon — ignore it.)
Activation errors (on activate)
| HTTP | type | Meaning |
|---|---|---|
429 | capacity_exceeded | Activating would exceed your plan's dedicated-GPU ceiling. |
409 | no_dedicated_capacity | No dedicated serving capacity available for this adapter's base model. |
409 | adapter_not_ready | The pinned adapter isn't in a Ready state. |
404 | — | Endpoint not found / not yours. |
Chat completions
Point the OpenAI SDK at the base URL; use the endpoint id as model.
model? Your Endpoint ID — the
copyable id shown in the Endpoints table under
Developer in your dashboard (a value like
df610c4483b04f9aa960f51624128796). It is not the base model
name (e.g. Llama), not your world or character name, and carries no version
number — the endpoint is already pinned to one specific trained version.
Python
from openai import OpenAI
client = OpenAI(base_url="https://api.thesuperposition.ai/v1", api_key="tsk_your_key_here")
resp = client.chat.completions.create(
model="df610c4483b04f9aa960f51624128796", # your endpoint id
messages=[
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Introduce yourself."},
],
temperature=0.4,
max_tokens=256,
)
print(resp.choices[0].message.content)
curl
curl https://api.thesuperposition.ai/v1/chat/completions \
-H "Authorization: Bearer tsk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"model": "df610c4483b04f9aa960f51624128796",
"messages": [{"role": "user", "content": "Introduce yourself."}]
}'
Response
{
"id": "chatcmpl-…",
"object": "chat.completion",
"created": 1752696000,
"model": "df610c4483b04f9aa960f51624128796",
"choices": [
{ "index": 0, "message": { "role": "assistant", "content": "…" }, "finish_reason": "stop" }
],
"usage": { "prompt_tokens": 12, "completion_tokens": 40, "total_tokens": 52 }
}
usage is an estimate (~4 chars/token) in v1, not an exact token count.
Alternate path form. You may also target the endpoint in the
URL and omit model: POST /v1/endpoints/{id}/chat/completions.
The model-field form is preferred (it's what stock SDKs send).
Streaming
Set stream: true. The response is Server-Sent Events (text/event-stream): a sequence of data: {chunk} lines terminated by data: [DONE].
stream = client.chat.completions.create(
model="df610c4483b04f9aa960f51624128796",
messages=[{"role": "user", "content": "Tell me a short story."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content:
print(delta.content, end="", flush=True)
Each chunk is a chat.completion.chunk. The first carries delta.role = "assistant"; content chunks carry delta.content; the final chunk has an empty delta with finish_reason: "stop", then [DONE]. This matches OpenAI's stream shape, so any OpenAI-compatible streaming client works unchanged.
Supported parameters
| Field | Notes |
|---|---|
model | Required. Your endpoint id. |
messages | Required. Array of { role, content }; roles system / user / assistant. A system message, if used, must be the first entry (see below). |
temperature | Optional. |
max_tokens | Optional. |
top_p | Optional. |
stop | Optional. String or array of strings. |
stream | Optional, default false. |
Unsupported OpenAI params (tools/function calling, n > 1, logprobs, response_format, image/audio content, …) are ignored, not errored. The adapter serves its own trained persona; you don't need to supply a system prompt to get its voice (though you may add one).
system message must be the first message. If you send a
system message, it has to be the very first entry in messages. A
system message in any other position causes the whole request to fail
(400 invalid_request_error) — so there's effectively at most one, and it's always
first. A system message is entirely optional: put your instructions in that leading
system message, or just include them in your user / assistant
messages instead.
Inference errors
OpenAI-shaped { "error": { "type", "code", "message" } }.
| HTTP | type / code | Meaning & what to do |
|---|---|---|
401 | invalid_api_key | Bad/missing key. |
404 | model_not_found | Endpoint id unknown or not yours. |
409 | endpoint_not_live | Endpoint is inactive. Activate it (Managing activation) and poll status until live before retrying. |
400 | invalid_request_error | Missing messages/model, empty body, or a system message that isn't the first message. Fix the request. |
502 | server_error | Upstream model error. Retry with backoff. |
Limits & behavior (v1)
- Text only. No audio/image/voice.
- Stateless. Send the full message history each call; nothing is stored between calls.
- Activate before you call. Inactive endpoints return
409 endpoint_not_live; inference never triggers activation. - Dedicated capacity. Each active endpoint runs on a GPU reserved for you — predictable latency, but you're billed for active time, so deactivate (or use TTL / scheduled) when idle.
- Pinned version. An endpoint serves the exact adapter version pinned to it; retraining doesn't change what it serves until the owner promotes the new version.
Create a key and endpoint under Developer in your dashboard, then activate it and make your first call.