Adapter API

An OpenAI Chat Completions-compatible API for your trained models. Point the standard SDK at our base URL, pass your endpoint ID as the model, and control when the model is active.

https://api.thesuperposition.ai/v1
View Markdown

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

TermMeaning
EndpointThe 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 keyYour secret (tsk_…). Authenticates every inference and activation call. Shown once when created; store it securely. Sent as a Bearer token.
Active / liveAn 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.
StatelessNo 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
Inference never activates an endpoint. A call to an inactive endpoint returns 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. After activate, poll until live: 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_until as the human "active until" time. (ready_until may also appear; it's an internal lease horizon — ignore it.)

Activation errors (on activate)

HTTPtypeMeaning
429capacity_exceededActivating would exceed your plan's dedicated-GPU ceiling.
409no_dedicated_capacityNo dedicated serving capacity available for this adapter's base model.
409adapter_not_readyThe pinned adapter isn't in a Ready state.
404Endpoint not found / not yours.

Chat completions

Point the OpenAI SDK at the base URL; use the endpoint id as model.

What goes in 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

FieldNotes
modelRequired. Your endpoint id.
messagesRequired. Array of { role, content }; roles system / user / assistant. A system message, if used, must be the first entry (see below).
temperatureOptional.
max_tokensOptional.
top_pOptional.
stopOptional. String or array of strings.
streamOptional, 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).

A 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" } }.

HTTPtype / codeMeaning & what to do
401invalid_api_keyBad/missing key.
404model_not_foundEndpoint id unknown or not yours.
409endpoint_not_liveEndpoint is inactive. Activate it (Managing activation) and poll status until live before retrying.
400invalid_request_errorMissing messages/model, empty body, or a system message that isn't the first message. Fix the request.
502server_errorUpstream 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.