DOCS

Developer docs

Last updated 2026-09-02

Quick start

Plenum Cloud exposes an OpenAI-compatible API. Existing OpenAI SDK projects migrate by changing only base_url and the API key.

1. Register and create a key under "API Keys" in the console (plaintext shown once). 2. Point base_url at Plenum. 3. Call as usual.

migration = one line ↓
from openai import OpenAI

client = OpenAI(
    base_url="https://api.plenumcloud.ai/v1",
    api_key="pln-...",
)

stream = client.chat.completions.create(
    model="gpt-5-mini",
    messages=[{"role": "user", "content": "Hello, Plenum"}],
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")
Streaming: the final SSE chunk carries usage (metering basis)

API

EndpointDescription
POST /v1/chat/completionsChat completions with streaming. Request/response shapes match OpenAI; streaming uses SSE and the final chunk carries usage.
GET /v1/modelsModels currently routable.
GET /healthzPublic health check returning ok; the status page probes it.

Authentication

All /v1 requests use Authorization: Bearer <API key>. Keys start with pln-; revocation takes effect immediately.

Streaming

Set stream: true. The gateway automatically injects stream_options.include_usage so the final SSE chunk carries usage — the basis for metering; no manual setup needed.

Metering & usage

Each request is metered and priced across four token classes, reported in the usage object:

FieldMeaning
usage.prompt_tokensTotal input tokens (including cached)
usage.prompt_tokens_details.cached_tokensInput tokens served from prefix cache, billed at a much lower rate
usage.completion_tokensOutput tokens
usage.completion_tokens_details.reasoning_tokensChain-of-thought tokens for reasoning models (when returned)

The console "Usage" and "Billing" views use the same definitions and drill down by model and key; invoices follow platform metering.

Prefix caching

Cached input tokens cost far less than uncached ones, and the saving is passed through in pricing. Agent workloads (long system prompts, tool definitions, multi-turn history) hit naturally — provided the prefix is byte-stable:

PracticeWhy
Put the system prompt and tool definitions first and keep them fixedCaching matches by prefix; any change early in the sequence invalidates everything after it
Place dynamic content (timestamps, user names, retrieved docs) at the endPreserves the shared prefix
Append messages in multi-turn rather than rewriting historyEarlier turns' KV state is reused directly

Hit rate is observable per key in the console.

Rate limits & quotas

Each API key has its own per-minute request limit (token bucket with short bursts) and an optional monthly token quota. Exceeding either returns 429 with error.code identifying the cause; clients should retry with exponential backoff. Dedicated-endpoint limits follow the contract.

Error codes

Errors follow the OpenAI shape: { "error": { "code", "message" } }.

HTTPcodeMeaning
400bad_requestBody is not valid JSON or lacks required fields
401invalid_api_keyKey invalid or revoked
429rate_limit_exceededPer-minute request limit exceeded; retry later
429insufficient_quotaMonthly token quota exhausted
502upstream_errorAll candidate upstreams unavailable (after automatic retry and failover)
502dedicated_unavailableThe node bound to your dedicated endpoint is unavailable; dedicated traffic never falls back to the shared pool

4xx errors are not retried; connection failures, 5xx and upstream 429s fail over across candidate upstreams automatically.

Dedicated endpoints

A dedicated endpoint is exclusive inference capacity: your requests route only to the node bound to you, never shared with other customers or subject to shared-pool limits; billed by capacity × time regardless of token usage.

StepDescription
1Submit a request under "Dedicated" in the console: model, GPU type, count
2Operations reviews, binds a node and confirms the hourly rate; status moves from pending to running and billing starts
3From then on, calling that model with your API key pins to the dedicated node automatically
4Release the instance in the console to stop billing; invoices show dedicated capacity as monthly line items

Compute onboarding

Teams with idle GPUs can list clusters for rent. Requirement: the node exposes an OpenAI-compatible streaming chat-completions endpoint (vLLM / SGLang etc.), reachable over the internet or a private link.

StepDescription
1Register the node under "Compute" in the console: name, endpoint, credentials, models served, hourly rate
2The platform probes the node periodically with real inference requests (not /healthz), recording TTFT, throughput and failure rate
3After manual approval the node joins scheduling; traffic is allocated by measured performance, and consecutive failures remove it temporarily
4Every request served by your node is metered line by line; request and token counts are visible in the console and settled monthly

Console API

The management API behind the console lives under /admin/v1, authenticated with a session token (Authorization: Bearer <session>), separate from API keys. Useful for automating usage and billing queries:

EndpointDescription
POST /admin/v1/auth/loginEmail + password → session token (valid 7 days; changing the password revokes sessions on other devices)
GET /admin/v1/meCurrent account status: pending / active / rejected. New accounts must be approved by an administrator (active) before using other endpoints or the API
GET /admin/v1/keys · POST · DELETE /{id}List / create / revoke keys
GET /admin/v1/usage · /usage/seriesUsage totals and time series (by model, by key)
GET /admin/v1/billingInvoice: usage lines + dedicated capacity monthly slices
GET /admin/v1/logsRequest log (own keys only)
GET /admin/v1/nodes · /instancesCompute nodes and dedicated instances
GET · POST /admin/v1/topupsTop-up orders: WeChat QR (credited instantly on payment) or bank transfer (credited once finance confirms)
GET /admin/v1/earnings · POST /admin/v1/payoutsSupplier earnings (by node × month) and payout requests
POST /admin/v1/chat?key=<id>Used by the console Playground: metered to one of your API keys; body identical to /v1/chat/completions
For live availability see the status page; for enterprise deployment, VPC and private options see Enterprise。