PlatformAPI documentation

Developer docs

Power Champion API Developer Guide

The complete guide to the OpenAI-compatible HTTPS API: authentication and keys, models and pricing, endpoint parameters, billing, rate limits and error handling.

Version 1.0 · 2026-10-20

← Back to the quick start

1. Overview

The Power Champion API is an OpenAI-compatible HTTPS interface. One key gives you chat, vision, embeddings, reranking, image generation, video generation, text to speech and speech recognition. Existing OpenAI SDKs work once you change the base_url and the key.

ItemValue
Document version1.0 (2026-10-20)
EnvironmentProduction
Base URLhttps://b300.powerchampion.ai/v1
ProtocolHTTPS only
Request formatJSON (Content-Type: application/json); speech recognition uses multipart/form-data
Character encodingUTF-8
CurrencyUS dollars (USD), prepaid
Online versionpowerchampion.ai/docs/api

Capabilities

CapabilityEndpointModels
Chat and reasoningPOST /v1/chat/completionsglm-5.2-fp8, glm-5.3-flash-uncensored
VisionPOST /v1/chat/completionsqwen3-vl-30b
Text completionsPOST /v1/completionsChat models
Text embeddingsPOST /v1/embeddingsbge-m3
Document rerankingPOST /v1/rerankbge-reranker-v2-m3
Image generationPOST /v1/images/generationsflux-schnell, chroma1-hd
Video generationPOST /v1/videos (asynchronous job)wan2.2-ti2v-5b-720p
Text to speechPOST /v1/audio/speechindextts2
Speech recognitionPOST /v1/audio/transcriptionswhisper-large-v3

Conventions

  • A missing required field returns 400 or 404. Optional fields fall back to their defaults when omitted.
  • $PC_API_KEY in the examples stands for your key. Keep it in an environment variable, not in your code.
  • Amounts are in US dollars. Billing endpoints also return exact values in nano-dollars (10⁻⁹ USD).
  • All times are UTC. Daily quotas reset at 00:00 UTC (08:00 Taiwan time).
  • Whether a model is online is defined by the service status. This guide does not guarantee that any particular model is available at all times.

2. Quick start

Three steps to your first request: get a key, set an environment variable, and send a request.

  1. Get a key: email info@powerchampion.org to apply. Keys start with sk-b300- and are issued by our team and sent to you. The platform stores only a hash, so a key cannot be recovered — keep it safe.
  2. Add credit: when you buy a credit pack you receive a redeem code. Apply it with POST /v1/redeem (see section 10).
  3. Set the environment variable:
bash
export PC_API_KEY="sk-b300-..."

curl

bash
curl https://b300.powerchampion.ai/v1/chat/completions \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.2-fp8",
    "messages": [{"role": "user", "content": "Describe Taipei in one sentence."}],
    "max_tokens": 512
  }'

Python

Install: pip install openai.

python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://b300.powerchampion.ai/v1",
    api_key=os.environ["PC_API_KEY"],
)

resp = client.chat.completions.create(
    model="glm-5.2-fp8",
    messages=[{"role": "user", "content": "Describe Taipei in one sentence."}],
    max_tokens=512,
)
print(resp.choices[0].message.content)
print(resp.usage)

Node.js

Install: npm install openai. Requires Node.js 18 or later, running as ESM (a .mjs file, or "type": "module" in package.json).

javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://b300.powerchampion.ai/v1",
  apiKey: process.env.PC_API_KEY,
});

const resp = await client.chat.completions.create({
  model: "glm-5.2-fp8",
  messages: [{ role: "user", content: "Describe Taipei in one sentence." }],
  max_tokens: 512,
});
console.log(resp.choices[0].message.content);

Successful response

json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1792483207,
  "model": "glm-5.2-fp8",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Taipei is the capital of Taiwan, …" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 14, "completion_tokens": 27, "total_tokens": 41 }
}

A 502 means the model is temporarily offline. Check the service status and switch to a model whose ready is true.

3. Authentication and key management

Every /v1/* and /dashboard/billing/* request must carry a Bearer key in its headers. No other authentication method is accepted.

http
Authorization: Bearer sk-b300-...
ItemDetails
Formatsk-b300- followed by 43 characters
StorageThe platform stores only a hash and cannot recover the original key. If you lose it, request a new one.
Issuing and revokingHandled by Power Champion. There is no self-service API for requesting or revoking keys yet.
Where to use itServer side only. The platform does not enable CORS, so browser code cannot call it directly.
Restricted keysSome keys are limited to specific models and have an expiry date. Requests outside that scope, or after expiry, return 403.

Authentication failures

StatusMessageWhat to do
401Missing bearer token. Send: Authorization: Bearer <key>Check the header name and the Bearer prefix
401Invalid API key.The key is wrong or disabled — contact us
403Reviewer API key is not permitted for this endpoint or model.A restricted key was used outside its scope or after it expired

Key security

  • Use a separate key for each environment (development, testing, production) so you can disable one without affecting the others.
  • Keep keys in environment variables or a secrets manager. Never commit them to version control or ship them in front-end code.
  • If you suspect a key has leaked, email info@powerchampion.org right away to disable it and get a new one.

4. Model catalog and pricing

Nine models are available in production. Prices below are list prices on 2026-10-20. The authoritative source is the public catalog.json; if the two differ, catalog.json wins.

Language and vision models

Model idUseContextMax outputInput (US$ / 1M tokens)Output (US$ / 1M tokens)FeaturesStatus now
glm-5.2-fp8Chat, reasoning, code131,07232,7680.933.00Tool calling, JSON output, structured output, reasoningOffline
glm-5.3-flash-uncensoredFast chat32,76832,7680.301.00Tool calling, JSON output, reasoning; no built-in content filtering — use is subject to the Terms of ServiceOffline
qwen3-vl-30bImage understanding, document recognition32,7684,0960.301.20Up to 4 images per request, tool calling, JSON output, structured outputOffline

Retrieval models

Model idUseContextPriceStatus now
bge-m3Text embeddings (1,024 dimensions)8,192US$0.02 per 1M input tokensOffline
bge-reranker-v2-m3Document reranking8,192US$0.02 per 1M input tokensOffline

Generation and speech models

Model idUseBilling unitPriceStatus now
flux-schnellFast image generationPer imageUS$0.01Offline
chroma1-hdHigh-quality image generation, supports negative promptsPer imageUS$0.01Offline
indextts2Text to speech with emotion controlPer minute of audioUS$0.03Offline
whisper-large-v3Speech recognition; Chinese output in Traditional Chinese (Taiwan)Per minute of audioAbout US$0.01Offline

“Status now” comes from the live status feed and refreshes about once a minute.

Video models

Model idUseBilling unitPrice
wan2.2-ti2v-5b-720pText-to-video and image-to-video, 1280×704 at 24 fps, 1–10 secondsPer output secondUS$0.05

Whether a video model is listed is defined by GET /v1/models (output_modalities contains video). Usage and billing are in section 9.

Availability

A model can go offline temporarily for maintenance or under load. Before calling one, check GET https://b300.powerchampion.ai/status.json (no key needed): only models whose ready is true are available. Calling GET /v1/models with your key returns the models that key can use and their per-token prices.

bash
curl https://b300.powerchampion.ai/v1/models \
  -H "Authorization: Bearer $PC_API_KEY"

Each entry in /v1/models has id, context_length, max_output_tokens, pricing (US dollars per token, as strings), endpoint, input_modalities, output_modalities and supported_features. For non-text models, max_output_tokens is not the actual output limit.

5. Chat API

POST /v1/chat/completions uses the same request and response format as OpenAI Chat Completions, and supports streaming, tool calling, JSON output and image input.

Request parameters

ParameterTypeRequiredDescription
modelstringYesModel id; see section 4
messagesarrayYesConversation messages; role is system, user, assistant or tool
max_tokensintegerNoMaximum tokens to generate. If it exceeds the model limit or the remaining context, the platform lowers it automatically instead of returning an error
max_completion_tokensintegerNoSame as max_tokens
temperaturenumberNoSampling temperature; lower is more deterministic
top_pnumberNoNucleus sampling ratio
streambooleanNoWhen true, the response is streamed as SSE
stopstring or arrayNoStop sequences
toolsarrayNoFunction definitions the model may call
tool_choicestring or objectNoauto, none, or a specific function
response_formatobjectNo{"type":"json_object"} or {"type":"json_schema", ...}
seedintegerNoFixed sampling seed for more reproducible results

top_p, stop, seed and other OpenAI-compatible parameters are passed straight to the model, so their effect depends on the model. Parameters a model does not support may be ignored or return 400 — test before you go live.

Response fields

FieldDescription
choices[].message.contentThe model's answer
choices[].message.tool_callsTools the model wants to call (when tools are used)
choices[].finish_reasonstop, length (hit max_tokens) or tool_calls
usageprompt_tokens, completion_tokens, total_tokens — the basis for billing

Streaming

With stream: true, the response is text/event-stream. Each event is one data: {...} line, and the stream ends with data: [DONE].

  • The platform turns on usage reporting, so any chunk may carry usage, and there may be a final chunk whose choices is an empty array. Check that the array is not empty before reading choices[0].
  • If the backend fails after the stream has started, the connection simply closes without an error event. Tokens already generated are still billed.
python
stream = client.chat.completions.create(
    model="glm-5.2-fp8",
    messages=[{"role": "user", "content": "List three sights in Tainan"}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

Tool calling

When you provide tools, the model may return tool_calls. Your code runs the tool and sends the result back as a role: "tool" message; the model then produces its final answer. In streaming mode, tool-call arguments arrive split across several chunks — concatenate them yourself.

python
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Look up the weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

resp = client.chat.completions.create(
    model="glm-5.2-fp8",
    messages=[{"role": "user", "content": "What's the weather in Taichung right now?"}],
    tools=tools,
)
call = resp.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)

JSON output

response_format: {"type": "json_object"} asks the model to output valid JSON only. Describe the fields in your prompt as well. When you need strict fields, use json_schema instead (supported only by glm-5.2-fp8 and qwen3-vl-30b).

Reasoning models

glm-5.2-fp8 and glm-5.3-flash-uncensored support reasoning. The thinking process may use up part of max_tokens and may count toward output token usage. If a response has an empty content and finish_reason is length, raise max_tokens.

Image input

Use qwen3-vl-30b and put image_url entries in the content array, up to 4 images per request. Sending images as data: base64 is recommended.

python
import base64

with open("invoice.jpg", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = client.chat.completions.create(
    model="qwen3-vl-30b",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "List the items and amounts on this invoice"},
            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
        ],
    }],
)

Personas

Power Champion can set up a fixed persona for you. Call GET /v1/personas/{persona_id} to get its messages_prefix and put it at the start of messages on every request. A fixed prefix hits the cache and lowers time to first token. Add ?rev=N to get a specific version; we provide the persona id.

json
{
  "persona_id": "...",
  "name": "Support assistant",
  "rev": 3,
  "updated": "...",
  "messages_prefix": [{ "role": "system", "content": "..." }]
}

6. Completions, embeddings and reranking APIs

Text completions POST /v1/completions

Legacy single-prompt completion in the OpenAI Completions format, with stream support. It works only with chat models; new projects should use the Chat API.

bash
curl https://b300.powerchampion.ai/v1/completions \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "glm-5.2-fp8", "prompt": "The highest mountain in Taiwan is", "max_tokens": 32}'

Text embeddings POST /v1/embeddings

ParameterTypeRequiredDescription
modelstringYesbge-m3
inputstring or arrayYesA single text or an array of texts, each up to 8,192 tokens
encoding_formatstringNoOnly float is supported
dimensionsintegerNoOnly 1024 is supported
python
resp = client.embeddings.create(
    model="bge-m3",
    input=["Taipei Metro operating hours", "High-speed rail fares"],
    encoding_format="float",
)
vectors = [d.embedding for d in resp.data]  # 1,024 dimensions each

The response uses the OpenAI embeddings format: data[].embedding, data[].index and usage.prompt_tokens.

Document reranking POST /v1/rerank

Reorders documents by how relevant they are to a query — typically used to refine results after vector retrieval.

ParameterTypeRequiredDescription
modelstringYesbge-reranker-v2-m3
querystringYesThe query
documentsarray of stringYesDocuments to rank
top_nintegerNoReturn only the top N results, 1–100
return_documentsbooleanNoWhether to include the document text in the results
bash
curl https://b300.powerchampion.ai/v1/rerank \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bge-reranker-v2-m3",
    "query": "How do I request a refund?",
    "documents": ["Refunds must be requested within 7 days", "Shipping is charged by weight", "Members earn points"],
    "top_n": 2
  }'
json
{
  "id": "rerank-...",
  "model": "bge-reranker-v2-m3",
  "results": [
    { "index": 0, "relevance_score": 0.9821 },
    { "index": 2, "relevance_score": 0.0137 }
  ],
  "usage": { "total_tokens": 46 }
}

results is sorted by relevance_score, highest first, and index points to the position in the original documents. Billing is based on the input tokens of the query and documents.

7. Image generation API

POST /v1/images/generations (also available as POST /v1/images) generates PNG images from text and returns them as base64. The endpoint accepts only the fields below; any other field returns 400.

Request parameters

ParameterTypeRequiredDescription
modelstringYesflux-schnell or chroma1-hd
promptstringYesDescription of the image
nintegerNoNumber of images, 1–4, default 1; billed per image
sizestringNoWIDTHxHEIGHT, each side 256–1536, rounded down to a multiple of 16; default 1024x1024
seedintegerNo0–4294967295; fix it to reproduce a result
stepsintegerNoflux-schnell: default 4, max 8. chroma1-hd: default 25, max 50
negative_promptstringNoWhat you do not want in the image; recommended for chroma1-hd only
guidance_scalenumberNoHow closely to follow the prompt; chroma1-hd only
stylestringNoPortrait layout presets: person, person_scene, object. They rewrite the prompt and add a negative prompt automatically — leave unset for general use
response_formatstringNoOnly b64_json is supported; image URLs are not provided

Example

python
import base64

resp = client.images.generate(
    model="flux-schnell",
    prompt="Jiufen Old Street in morning light, photorealistic",
    size="1024x1024",
    n=1,
    extra_body={"seed": 7},
)
with open("jiufen.png", "wb") as f:
    f.write(base64.b64decode(resp.data[0].b64_json))

Response

json
{
  "created": 1792483207,
  "data": [{ "b64_json": "iVBORw0KGgo...", "media_type": "image/png" }],
  "seed": 7,
  "steps": 4,
  "model": "flux-schnell",
  "guidance_scale": 0.0,
  "usage": { "prompt_tokens": 0, "completion_tokens": 1000, "total_tokens": 1000 }
}

Which model to choose

  • flux-schnell: speed first — suited to large batches of drafts and real-time generation inside a product.
  • chroma1-hd: quality first, with negative prompts and guidance_scale — suited to production assets.

Both cost US$0.01 per image. flux-schnell accepts negative_prompt, but it has almost no effect and makes generation slower; if you need a negative prompt, use chroma1-hd.

8. Text-to-speech and speech recognition APIs

Text to speech POST /v1/audio/speech

Turns text into speech, with emotion controlled by a text description. The response is the audio file itself. Streaming is not supported: the audio is returned once synthesis is complete, and the backend timeout is 300 seconds.

ParameterTypeRequiredDescription
modelstringYesindextts2
inputstringYesText to synthesize, up to 2,000 characters
voicestringYesVoice id provided by Power Champion; an unregistered voice returns 400
response_formatstringNomp3 (default), opus (Ogg container), wav
speednumberNoNot currently supported by indextts2; ignored
instructstringNoEmotion description, for example “開心、雀躍” (happy, excited)
emo_alphanumberNoEmotion strength, 0–1; 0.6 recommended

Response headers: X-Audio-Seconds is the audio length in seconds, and X-Usage-Tokens is the billed amount (50 tokens per second).

bash
curl https://b300.powerchampion.ai/v1/audio/speech \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "indextts2",
    "input": "您好,歡迎來電,請問有什麼可以為您服務?",
    "voice": "<音色 id>",
    "instruct": "親切、溫和",
    "emo_alpha": 0.6
  }' \
  --output greeting.mp3

Split long text by sentence and synthesize each part separately. You wait less, and you stay under the 2,000-character limit.

Speech recognition POST /v1/audio/transcriptions

Transcribes audio to text. Chinese results are converted to Traditional Chinese (Taiwan). Upload the request as multipart/form-data.

ParameterTypeRequiredDescription
filefileYesAudio file, up to 25 MB; keep each segment to 600 seconds or less
modelstringYeswhisper-large-v3
languagestringNozh or en; detected automatically when left empty
promptstringNoHints for proper nouns or terminology, which can improve accuracy
response_formatstringNojson (default, includes usage) or text
temperaturenumberNo0–1
bash
curl https://b300.powerchampion.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $PC_API_KEY" \
  -F file=@meeting.mp3 \
  -F model=whisper-large-v3 \
  -F language=zh
json
{
  "text": "今天的會議重點有三個…",
  "language": "zh",
  "duration": 42.6,
  "usage": { "prompt_tokens": 0, "completion_tokens": 2130, "total_tokens": 2130 }
}

Formats whose length can be read (such as wav and flac) return 400 when longer than 600 seconds; other formats are not guaranteed to be checked. Uploads over 25 MB return 413. Split long recordings into segments of 10 minutes or less before uploading.

9. Video generation API

POST /v1/videos generates an MP4 video from text, or from text plus one image. Video generation takes time, so it is an asynchronous job: submit the job, poll its status, then download the result. Authentication is the same as for every other endpoint: one key.

Available model

Model idInputOutputLength
wan2.2-ti2v-5b-720pText, or text plus one imageMP4, 1280×704, 24 fps1–10 seconds

Whether the model is listed is defined by GET /v1/models (output_modalities contains video). Resolution and frame rate are fixed and cannot be set in the request; a request that includes a field not in the table below (for example resolution) returns 400.

Flow

  1. POST /v1/videos: submit the job. Returns 202 with the job id (status queued).
  2. GET /v1/videos/{id}: poll the status, about every 5 seconds, until it is succeeded, failed, cancelled or expired.
  3. GET /v1/videos/{id}/content: once succeeded, download the MP4.

Request parameters

ParameterTypeRequiredDescription
modelstringYeswan2.2-ti2v-5b-720p
promptstringYesDescription of the video; non-empty, up to 2000 characters
negative_promptstringNoUp to 500 characters. The backend does not apply this field yet (accepted but ignored)
imagestringNoStarting frame as base64; a data URL prefix such as data:image/png;base64, is allowed. At most 6,000,000 bytes after decoding, otherwise 413. With an image the job is image-to-video; without one it is text-to-video
secondsintegerNoA JSON integer from 1 to 10, default 5. 5.0, "5" and true are rejected
seedintegerNo0–4294967295; random if omitted

Example

bash
curl https://b300.powerchampion.ai/v1/videos \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan2.2-ti2v-5b-720p",
    "prompt": "A red fox walks through fresh snow at dawn",
    "seconds": 5
  }'

Success returns 202:

json
{
  "id": "0f3c…",
  "object": "video.job",
  "status": "queued",
  "model": "wan2.2-ti2v-5b-720p",
  "mode": "t2v",
  "seconds": 5,
  "estimated_cost_usd": "0.25",
  "expires_at": null,
  "created_at": 1760000000.0
}

The complete flow (submit, poll, download):

bash
JOB=$(curl -s https://b300.powerchampion.ai/v1/videos \
  -H "Authorization: Bearer $PC_API_KEY" -H "Content-Type: application/json" \
  -d '{"model":"wan2.2-ti2v-5b-720p","prompt":"A red fox walks through fresh snow at dawn","seconds":5}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')

while :; do
  S=$(curl -s -H "Authorization: Bearer $PC_API_KEY" https://b300.powerchampion.ai/v1/videos/$JOB \
      | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')
  echo "$S"; case "$S" in succeeded|failed|cancelled|expired) break;; esac; sleep 5
done

curl -s -o out.mp4 -H "Authorization: Bearer $PC_API_KEY" https://b300.powerchampion.ai/v1/videos/$JOB/content

Checking a job and job statuses

json
{
  "id": "0f3c…",
  "object": "video.job",
  "model": "wan2.2-ti2v-5b-720p",
  "status": "succeeded",
  "progress": 1.0,
  "mode": "t2v",
  "seconds": 5,
  "output_seconds": 5.041667,
  "cost_usd": "0.252090",
  "error": null,
  "content_url": "/v1/videos/0f3c…/content",
  "expires_at": 1760086400.0,
  "created_at": 1760000000.0,
  "finished_at": 1760000300.0
}
statusMeaning
queuedAccepted and waiting (the brief stage in which the balance is still being reserved also shows as queued)
processingGenerating; progress runs from 0 to 1
succeededFinished and ready to download; content_url is set. cost_usd is null until settlement completes (usually within seconds), then holds the settled amount
failedFailed or timed out (a single job is limited to 30 minutes); error gives the reason, the reservation is released, and nothing is charged
cancelledCancelled; nothing is charged
expiredThe retention period has passed; downloading returns 410

expires_at and finished_at are Unix timestamps in seconds. About 7 days after a job expires its record is deleted and lookups return 404; until then the expired status can still be read.

Pricing and settlement

  • US$0.05 per second of output video.
  • Billed on the actual output length, capped at 1.1 times the requested seconds. The actual length can be slightly longer than requested (frames = seconds × fps + 1, so 5 seconds → 121 frames ≈ 5.04 seconds, about US$0.252).
  • At submission, balance for the requested seconds × 1.1 is reserved (for example 5 seconds → 5.5 seconds = US$0.275). On completion the job is settled on the actual length and the difference is refunded.
  • If a job fails, times out, or is cancelled while queued, the whole reservation is released and nothing is charged.
  • The settled amount appears in cost_usd after completion; the estimated_cost_usd returned at submission is requested seconds × the unit price.

Download and cancel

  • GET /v1/videos/{id}/content returns 200 with Content-Type: video/mp4, streamed. HTTP Range is supported: Range: bytes=… returns 206 (an invalid range returns 416), so downloads can resume.
  • A finished video can be downloaded for at least 24 hours; the exact deadline is the job's expires_at. An unfinished job returns 409; an expired one returns 410 (404 once the record is deleted about 7 days later).
  • DELETE /v1/videos/{id} cancels only queued jobs, with no charge, and returns {"id": "…", "status": "cancelled"}. A job that is processing or already finished returns 409; a job that has only just been submitted and is still being accepted can also return 409, so retry shortly. If the video backend is temporarily unreachable it returns 502 and the job is unchanged, so you can retry the cancel.

Errors on the video endpoints

StatusCase
400Field validation failed: an unknown field, an empty or over-long prompt, seconds that is not an integer from 1 to 10, seed out of range, image that is not valid base64, or a model that does not accept images
401Missing or invalid key
402Prepaid balance cannot cover the worst-case reservation (requested seconds × 1.1), or the balance is exhausted; top up
404The model does not exist, is not listed, or is not a video model; the job ID does not exist (another key's job also returns 404), or the job expired more than about 7 days ago and its record is deleted
409The state does not allow the operation: downloading an unfinished job, or cancelling a job that is not queued
410The video has expired
413image is larger than 6,000,000 bytes after decoding
429Capacity is full (code is capacity, with Retry-After: 15), the key already has 4 video jobs in progress, the per-minute request limit was exceeded, or the daily quota is used up. When Retry-After is present, retry after that time; the daily-quota 429 has no such header and resets at 00:00 UTC
502The backend responded abnormally during a download or cancel; retry later
503The backend cannot accept jobs right now (nothing was charged), the model is under maintenance, or the video backend is temporarily unreachable; retry later

When a submission gets 429 or 503, no balance was deducted and you can simply submit again.

10. Billing: credit, balance and usage

The platform is prepaid: you add credit first, and each request is charged for its actual usage once it completes. When the balance runs out, requests return 402. Failed requests, such as backend or validation errors, are not charged, and neither is a non-streaming request whose connection drops before the response arrives. If a stream is interrupted after it has started sending, the tokens already generated are still billed.

Credit packs

PlanYou payCreditedBonus
StarterUS$10US$10.00—
BuilderUS$50US$52.505%
ScaleUS$200US$224.0012%

Credit packs are delivered as redeem codes. Email info@powerchampion.org to buy one.

Redeem a code POST /v1/redeem

bash
curl https://b300.powerchampion.ai/v1/redeem \
  -H "Authorization: Bearer $PC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"code": "<redeem code>"}'
json
{ "ok": true, "credited_nano_usd": 10000000000, "new_balance_nano_usd": 12345000000 }
StatusMeaning
200Credited; amounts are in units of 10⁻⁹ USD
400No code, the body is not a JSON object, or this key does not support credit; the code is not consumed
404The code does not exist
409The code has already been used, disabled or expired

Balance and usage

EndpointReturnsNotes
GET /dashboard/billing/subscriptionplan.remaining_usdRemaining balance; excludes reservations for in-flight requests, so it may read slightly high
GET /dashboard/billing/usagetotal_usage, total_usage_nano_usdCumulative historical spend (USD); date ranges are not supported
bash
curl https://b300.powerchampion.ai/dashboard/billing/subscription \
  -H "Authorization: Bearer $PC_API_KEY"
json
{
  "object": "billing_subscription",
  "has_payment_method": true,
  "hard_limit_usd": 8.42,
  "system_hard_limit_usd": 8.42,
  "access_until": null,
  "plan": { "title": "prepaid", "remaining_usd": 8.42 }
}

There is no API for per-request records yet; ask us for a monthly report. Every response also reports usage: usage for text models, and the X-Usage-Tokens header for text to speech.

Billing rules

Every model uses the same formula, priced at the list price when the request is accepted:

Cost (US$) = (input tokens × input price + output tokens × output price) ÷ 1,000,000

Non-text models are first converted into equivalent tokens:

Model typeConversionResult
Image generation1,000 tokens per image × US$10 / 1MUS$0.01 per image
Text to speech50 tokens per second × US$10 / 1MUS$0.03 per minute
Speech recognition50 tokens per second × US$3.33 / 1MAbout US$0.01 per minute

Video generation does not use the token conversion above: it is priced per second of output video, reserved at submission and settled on completion with the difference refunded. See section 9.

Precision is 10⁻⁹ USD. Charges are applied after the response completes, so the last request can leave the balance slightly negative.

11. Rate limits and quotas

Each key has four limits, and each model also has an overall capacity limit. The actual settings for your key are those agreed when it was issued — ask us if you need them. The platform does not send X-RateLimit-* headers.

LimitRuleWhen exceededRetry-After
Requests per minute60-second sliding window429 Rate limit exceeded (N/min) for this key.2 seconds
Concurrent requestsA streaming request counts until it ends429 Key is at its concurrency limit1 second
Daily token quotaCounted per UTC day, resets at 00:00 UTC429 Daily token quota exhaustedNone
Prepaid balanceRejected once the balance runs out402 Prepaid balance exhausted0
Model capacityThe model is at full load overall429 Model '<id>' is at capacity2 seconds

How the daily quota is reserved

When a request is accepted, max_tokens (2,000 if not set) is reserved from the day's quota, then corrected to actual usage when the request completes; failed requests release their reservation. When the quota is nearly used up, a smaller max_tokens lets more requests through.

Recommendations

  • On a 429, wait for Retry-After and retry. If the daily quota is used up, wait until 00:00 UTC.
  • For high-concurrency applications, add a queue in your code to keep in-flight requests within your key's limit.
  • If you need higher limits, email info@powerchampion.org with your expected requests per minute, concurrency and daily usage.

12. Error handling

Errors use the OpenAI format. Only 429, 502 and 503 are worth retrying; for any other status code, fix the request first.

Error format

json
{
  "error": {
    "message": "Rate limit exceeded (60/min) for this key.",
    "type": "rate_limit_error",
    "param": null,
    "code": null
  }
}
`type`Status codes
authentication_error401 (code is invalid_api_key)
permission_error403
invalid_request_error400, 402, 404, 409, 413
rate_limit_error429 (code may be sellable_capacity_exhausted when a model is at capacity)
server_error500 and above

A few errors use {"detail": ...} instead: validation errors from the speech and image backends, 401 from /dashboard/billing/*, unknown paths (404), wrong methods (405) and query-parameter type errors (422). In addition, when the request body is not a JSON object (an array, for example), some endpoints may return a plain-text 500. Handle both formats when parsing errors. Error message text may change, so base your logic on the status code and type.

Status codes

StatusCommon causesWhat to do
400Malformed JSON, invalid field, context exceeded, audio over 600 seconds, unknown voiceFix the request; do not retry
401Missing or invalid keyCheck the Authorization header
402Prepaid balance exhaustedAdd credit, then try again
403Restricted key used outside its scope or expiredCheck your key's scope with us
404Model does not exist or is not available, redeem code does not exist, or unknown pathCheck the model id and path
409Redeem code already used, disabled or expiredContact us
413Speech recognition upload over 25 MBCompress or split the file and upload again
429Rate, concurrency or daily quota exceeded, or the model is at capacityWait for Retry-After, then retry
500Unexpected server errorRetry once; if it persists, contact us
502Model backend unreachable (All replicas failed)Retry with exponential backoff; if it keeps failing, check the service status or switch models
503Model under maintenance or being switchedWait for Retry-After (usually 30 or 600 seconds)

Check order

When a request has several problems at once, the platform checks them in the order below and returns the first failure. When debugging, work down the table from the top.

OrderCheckOn failure
1Is the key valid?401
2Is the request valid JSON?400
3Is the key allowed to use this endpoint and model?403
4Does the model exist and is it available?404
5Is the model under maintenance or being switched?503
6Concurrent in-flight requests for the key429
7Prepaid balance402
8Requests per minute429
9Daily token quota429
10Overall model capacity429
11Model backend processing400 or 502

Field-validation 400s (for example, an unsupported image field) and the speech-recognition 413 may be returned earlier than this order suggests.

Retry strategy

  1. Retry only 429, 502 and 503, plus network-level connection errors.
  2. If there is a Retry-After, wait that long. Otherwise use exponential backoff (1, 2, 4, 8 seconds) with random jitter, up to 4 attempts.
  3. Use streaming for generations expected to take longer than 60 seconds; non-streaming requests longer than about 100 seconds may be disconnected. If a long non-streaming request times out, check your balance or usage to see whether it was charged before you resend it.
python
import random, time
from openai import APIStatusError

RETRYABLE = {429, 502, 503}

def with_retry(call, attempts=4):
    for i in range(attempts):
        try:
            return call()
        except APIStatusError as e:
            if e.status_code not in RETRYABLE or i == attempts - 1:
                raise
            wait = e.response.headers.get("retry-after")
            time.sleep(float(wait) if wait else 2 ** i + random.random())

resp = with_retry(lambda: client.chat.completions.create(
    model="glm-5.2-fp8",
    messages=[{"role": "user", "content": "Hello"}],
))

With the official OpenAI SDK, you can also set max_retries when you create the client and let the SDK handle retries.

13. Best practices and security

Performance

  • Stream long answers: users see content right away, and you avoid proxy timeouts.
  • Put fixed prefixes first: keep system prompts and personas unchanged and at the start of messages to hit the prefix cache and lower time to first token.
  • Set a sensible max_tokens: it controls cost and reduces the daily-quota reservation.
  • Retrieve with embeddings, then rerank: take the top 50 candidates with bge-m3, then the top 5 with bge-reranker-v2-m3 for the chat model.
  • Split long audio: keep speech-recognition segments to 10 minutes or less, and split text to speech by sentence.

Reliability

  • Have a fallback model for important flows: when the primary model returns 502 or 503, switch to a chat model that the service status shows as ready.
  • Read status.json regularly for health checks instead of testing availability with real inference requests.
  • Log each request's time (UTC), model, status code and usage, and include them when you report a problem.

Cost control

  • Test with a small amount of credit before going live, and read /dashboard/billing/subscription regularly to watch the balance.
  • Accumulate cost in your own system from each response's usage, and alert when the balance drops below a threshold.
  • Choose flux-schnell when you only need drafts, and glm-5.3-flash-uncensored when you only need fast answers.

Security and compliance

  • Keep keys on the server. Front-end applications should go through your own backend.
  • Do not put passwords, keys or unnecessary personal data in prompts.
  • glm-5.3-flash-uncensored has no built-in content filtering. Add your own content moderation to products for the general public.
  • Have generated content reviewed by a person before publishing it, and label it as AI-generated where applicable law requires.
  • For how data is handled and retained, see the Privacy Policy and the Data Retention Policy.

14. Appendix

A. Endpoint index

MethodPathPurposeKey required
GET/v1/modelsList the models and prices available to your keyYes
POST/v1/chat/completionsChat, tool calling, image inputYes
POST/v1/completionsText completionsYes
POST/v1/embeddingsText embeddingsYes
POST/v1/rerankDocument rerankingYes
POST/v1/images/generations, /v1/imagesImage generationYes
POST/v1/audio/speechText to speechYes
POST/v1/audio/transcriptionsSpeech recognitionYes
POST/v1/videosSubmit a video generation jobYes
GET/v1/videos/{id}Check a video jobYes
GET/v1/videos/{id}/contentDownload the video (MP4)Yes
DELETE/v1/videos/{id}Cancel a queued video jobYes
GET/v1/personas/{persona_id}Read a personaYes
POST/v1/redeemRedeem a credit codeYes
GET/dashboard/billing/subscriptionCheck balanceYes
GET/dashboard/billing/usageCheck cumulative usageYes
GEThttps://b300.powerchampion.ai/status.jsonLive model statusNo
GEThttps://b300.powerchampion.ai/catalog.jsonPublic model catalog and list pricesNo
GEThttps://b300.powerchampion.ai/healthGateway liveness checkNo

B. Not currently supported

  • OpenAI Responses API, Assistants, Files, Batches, Moderations.
  • Audio translation /v1/audio/translations and realtime speech (Realtime / WebSocket).
  • Single-model lookup /v1/models/{id}.
  • Self-service key requests or revocation, online payment, a per-request usage API, and webhook notifications for request results.

C. Service status and support

ItemWhere
Service status pagepowerchampion.ai/status
Online developer docspowerchampion.ai/docs/api
Terms of Servicepowerchampion.ai/terms
Technical support and billinginfo@powerchampion.org

When reporting a problem, include the time (UTC), model id, endpoint, status code, the full error message, and the first 12 characters of your key (never the full key).

D. Changelog

DateVersionChanges
2026-10-201.0First release, covering the endpoints and models in sections 1–12.