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
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.
| Item | Value |
|---|---|
| Document version | 1.0 (2026-10-20) |
| Environment | Production |
| Base URL | https://b300.powerchampion.ai/v1 |
| Protocol | HTTPS only |
| Request format | JSON (Content-Type: application/json); speech recognition uses multipart/form-data |
| Character encoding | UTF-8 |
| Currency | US dollars (USD), prepaid |
| Online version | powerchampion.ai/docs/api |
Capabilities
| Capability | Endpoint | Models |
|---|---|---|
| Chat and reasoning | POST /v1/chat/completions | glm-5.2-fp8, glm-5.3-flash-uncensored |
| Vision | POST /v1/chat/completions | qwen3-vl-30b |
| Text completions | POST /v1/completions | Chat models |
| Text embeddings | POST /v1/embeddings | bge-m3 |
| Document reranking | POST /v1/rerank | bge-reranker-v2-m3 |
| Image generation | POST /v1/images/generations | flux-schnell, chroma1-hd |
| Video generation | POST /v1/videos (asynchronous job) | wan2.2-ti2v-5b-720p |
| Text to speech | POST /v1/audio/speech | indextts2 |
| Speech recognition | POST /v1/audio/transcriptions | whisper-large-v3 |
Conventions
- A missing required field returns 400 or 404. Optional fields fall back to their defaults when omitted.
$PC_API_KEYin 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.
- 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. - Add credit: when you buy a credit pack you receive a redeem code. Apply it with
POST /v1/redeem(see section 10). - Set the environment variable:
export PC_API_KEY="sk-b300-..."curl
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.
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).
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
{
"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.
Authorization: Bearer sk-b300-...| Item | Details |
|---|---|
| Format | sk-b300- followed by 43 characters |
| Storage | The platform stores only a hash and cannot recover the original key. If you lose it, request a new one. |
| Issuing and revoking | Handled by Power Champion. There is no self-service API for requesting or revoking keys yet. |
| Where to use it | Server side only. The platform does not enable CORS, so browser code cannot call it directly. |
| Restricted keys | Some keys are limited to specific models and have an expiry date. Requests outside that scope, or after expiry, return 403. |
Authentication failures
| Status | Message | What to do |
|---|---|---|
| 401 | Missing bearer token. Send: Authorization: Bearer <key> | Check the header name and the Bearer prefix |
| 401 | Invalid API key. | The key is wrong or disabled — contact us |
| 403 | Reviewer 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 id | Use | Context | Max output | Input (US$ / 1M tokens) | Output (US$ / 1M tokens) | Features | Status now |
|---|---|---|---|---|---|---|---|
glm-5.2-fp8 | Chat, reasoning, code | 131,072 | 32,768 | 0.93 | 3.00 | Tool calling, JSON output, structured output, reasoning | Offline |
glm-5.3-flash-uncensored | Fast chat | 32,768 | 32,768 | 0.30 | 1.00 | Tool calling, JSON output, reasoning; no built-in content filtering — use is subject to the Terms of Service | Offline |
qwen3-vl-30b | Image understanding, document recognition | 32,768 | 4,096 | 0.30 | 1.20 | Up to 4 images per request, tool calling, JSON output, structured output | Offline |
Retrieval models
| Model id | Use | Context | Price | Status now |
|---|---|---|---|---|
bge-m3 | Text embeddings (1,024 dimensions) | 8,192 | US$0.02 per 1M input tokens | Offline |
bge-reranker-v2-m3 | Document reranking | 8,192 | US$0.02 per 1M input tokens | Offline |
Generation and speech models
| Model id | Use | Billing unit | Price | Status now |
|---|---|---|---|---|
flux-schnell | Fast image generation | Per image | US$0.01 | Offline |
chroma1-hd | High-quality image generation, supports negative prompts | Per image | US$0.01 | Offline |
indextts2 | Text to speech with emotion control | Per minute of audio | US$0.03 | Offline |
whisper-large-v3 | Speech recognition; Chinese output in Traditional Chinese (Taiwan) | Per minute of audio | About US$0.01 | Offline |
“Status now” comes from the live status feed and refreshes about once a minute.
Video models
| Model id | Use | Billing unit | Price |
|---|---|---|---|
| wan2.2-ti2v-5b-720p | Text-to-video and image-to-video, 1280×704 at 24 fps, 1–10 seconds | Per output second | US$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.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Model id; see section 4 |
messages | array | Yes | Conversation messages; role is system, user, assistant or tool |
max_tokens | integer | No | Maximum 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_tokens | integer | No | Same as max_tokens |
temperature | number | No | Sampling temperature; lower is more deterministic |
top_p | number | No | Nucleus sampling ratio |
stream | boolean | No | When true, the response is streamed as SSE |
stop | string or array | No | Stop sequences |
tools | array | No | Function definitions the model may call |
tool_choice | string or object | No | auto, none, or a specific function |
response_format | object | No | {"type":"json_object"} or {"type":"json_schema", ...} |
seed | integer | No | Fixed 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
| Field | Description |
|---|---|
choices[].message.content | The model's answer |
choices[].message.tool_calls | Tools the model wants to call (when tools are used) |
choices[].finish_reason | stop, length (hit max_tokens) or tool_calls |
usage | prompt_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 whosechoicesis an empty array. Check that the array is not empty before readingchoices[0]. - If the backend fails after the stream has started, the connection simply closes without an error event. Tokens already generated are still billed.
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.
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.
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.
{
"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.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | bge-m3 |
input | string or array | Yes | A single text or an array of texts, each up to 8,192 tokens |
encoding_format | string | No | Only float is supported |
dimensions | integer | No | Only 1024 is supported |
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 eachThe 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.
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | bge-reranker-v2-m3 |
query | string | Yes | The query |
documents | array of string | Yes | Documents to rank |
top_n | integer | No | Return only the top N results, 1–100 |
return_documents | boolean | No | Whether to include the document text in the results |
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
}'{
"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
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | flux-schnell or chroma1-hd |
prompt | string | Yes | Description of the image |
n | integer | No | Number of images, 1–4, default 1; billed per image |
size | string | No | WIDTHxHEIGHT, each side 256–1536, rounded down to a multiple of 16; default 1024x1024 |
seed | integer | No | 0–4294967295; fix it to reproduce a result |
steps | integer | No | flux-schnell: default 4, max 8. chroma1-hd: default 25, max 50 |
negative_prompt | string | No | What you do not want in the image; recommended for chroma1-hd only |
guidance_scale | number | No | How closely to follow the prompt; chroma1-hd only |
style | string | No | Portrait layout presets: person, person_scene, object. They rewrite the prompt and add a negative prompt automatically — leave unset for general use |
response_format | string | No | Only b64_json is supported; image URLs are not provided |
Example
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
{
"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.
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | indextts2 |
input | string | Yes | Text to synthesize, up to 2,000 characters |
voice | string | Yes | Voice id provided by Power Champion; an unregistered voice returns 400 |
response_format | string | No | mp3 (default), opus (Ogg container), wav |
speed | number | No | Not currently supported by indextts2; ignored |
instruct | string | No | Emotion description, for example “開心、雀躍” (happy, excited) |
emo_alpha | number | No | Emotion 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).
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.mp3Split 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.
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Audio file, up to 25 MB; keep each segment to 600 seconds or less |
model | string | Yes | whisper-large-v3 |
language | string | No | zh or en; detected automatically when left empty |
prompt | string | No | Hints for proper nouns or terminology, which can improve accuracy |
response_format | string | No | json (default, includes usage) or text |
temperature | number | No | 0–1 |
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{
"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 id | Input | Output | Length |
|---|---|---|---|
wan2.2-ti2v-5b-720p | Text, or text plus one image | MP4, 1280×704, 24 fps | 1–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
POST /v1/videos: submit the job. Returns202with the jobid(statusqueued).GET /v1/videos/{id}: poll the status, about every 5 seconds, until it issucceeded,failed,cancelledorexpired.GET /v1/videos/{id}/content: oncesucceeded, download the MP4.
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | wan2.2-ti2v-5b-720p |
prompt | string | Yes | Description of the video; non-empty, up to 2000 characters |
negative_prompt | string | No | Up to 500 characters. The backend does not apply this field yet (accepted but ignored) |
image | string | No | Starting 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 |
seconds | integer | No | A JSON integer from 1 to 10, default 5. 5.0, "5" and true are rejected |
seed | integer | No | 0–4294967295; random if omitted |
Example
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:
{
"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):
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/contentChecking a job and job statuses
{
"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
}| status | Meaning |
|---|---|
queued | Accepted and waiting (the brief stage in which the balance is still being reserved also shows as queued) |
processing | Generating; progress runs from 0 to 1 |
succeeded | Finished and ready to download; content_url is set. cost_usd is null until settlement completes (usually within seconds), then holds the settled amount |
failed | Failed or timed out (a single job is limited to 30 minutes); error gives the reason, the reservation is released, and nothing is charged |
cancelled | Cancelled; nothing is charged |
expired | The 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_usdafter completion; theestimated_cost_usdreturned at submission is requested seconds × the unit price.
Download and cancel
GET /v1/videos/{id}/contentreturns200withContent-Type: video/mp4, streamed. HTTPRangeis supported:Range: bytes=…returns206(an invalid range returns416), 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 onlyqueuedjobs, with no charge, and returns{"id": "…", "status": "cancelled"}. A job that isprocessingor 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
| Status | Case |
|---|---|
| 400 | Field 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 |
| 401 | Missing or invalid key |
| 402 | Prepaid balance cannot cover the worst-case reservation (requested seconds × 1.1), or the balance is exhausted; top up |
| 404 | The 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 |
| 409 | The state does not allow the operation: downloading an unfinished job, or cancelling a job that is not queued |
| 410 | The video has expired |
| 413 | image is larger than 6,000,000 bytes after decoding |
| 429 | Capacity 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 |
| 502 | The backend responded abnormally during a download or cancel; retry later |
| 503 | The 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
| Plan | You pay | Credited | Bonus |
|---|---|---|---|
| Starter | US$10 | US$10.00 | — |
| Builder | US$50 | US$52.50 | 5% |
| Scale | US$200 | US$224.00 | 12% |
Credit packs are delivered as redeem codes. Email info@powerchampion.org to buy one.
Redeem a code POST /v1/redeem
curl https://b300.powerchampion.ai/v1/redeem \
-H "Authorization: Bearer $PC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code": "<redeem code>"}'{ "ok": true, "credited_nano_usd": 10000000000, "new_balance_nano_usd": 12345000000 }| Status | Meaning |
|---|---|
| 200 | Credited; amounts are in units of 10⁻⁹ USD |
| 400 | No code, the body is not a JSON object, or this key does not support credit; the code is not consumed |
| 404 | The code does not exist |
| 409 | The code has already been used, disabled or expired |
Balance and usage
| Endpoint | Returns | Notes |
|---|---|---|
GET /dashboard/billing/subscription | plan.remaining_usd | Remaining balance; excludes reservations for in-flight requests, so it may read slightly high |
GET /dashboard/billing/usage | total_usage, total_usage_nano_usd | Cumulative historical spend (USD); date ranges are not supported |
curl https://b300.powerchampion.ai/dashboard/billing/subscription \
-H "Authorization: Bearer $PC_API_KEY"{
"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 type | Conversion | Result |
|---|---|---|
| Image generation | 1,000 tokens per image × US$10 / 1M | US$0.01 per image |
| Text to speech | 50 tokens per second × US$10 / 1M | US$0.03 per minute |
| Speech recognition | 50 tokens per second × US$3.33 / 1M | About 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.
| Limit | Rule | When exceeded | Retry-After |
|---|---|---|---|
| Requests per minute | 60-second sliding window | 429 Rate limit exceeded (N/min) for this key. | 2 seconds |
| Concurrent requests | A streaming request counts until it ends | 429 Key is at its concurrency limit | 1 second |
| Daily token quota | Counted per UTC day, resets at 00:00 UTC | 429 Daily token quota exhausted | None |
| Prepaid balance | Rejected once the balance runs out | 402 Prepaid balance exhausted | 0 |
| Model capacity | The model is at full load overall | 429 Model '<id>' is at capacity | 2 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-Afterand 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
{
"error": {
"message": "Rate limit exceeded (60/min) for this key.",
"type": "rate_limit_error",
"param": null,
"code": null
}
}| `type` | Status codes |
|---|---|
authentication_error | 401 (code is invalid_api_key) |
permission_error | 403 |
invalid_request_error | 400, 402, 404, 409, 413 |
rate_limit_error | 429 (code may be sellable_capacity_exhausted when a model is at capacity) |
server_error | 500 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
| Status | Common causes | What to do |
|---|---|---|
| 400 | Malformed JSON, invalid field, context exceeded, audio over 600 seconds, unknown voice | Fix the request; do not retry |
| 401 | Missing or invalid key | Check the Authorization header |
| 402 | Prepaid balance exhausted | Add credit, then try again |
| 403 | Restricted key used outside its scope or expired | Check your key's scope with us |
| 404 | Model does not exist or is not available, redeem code does not exist, or unknown path | Check the model id and path |
| 409 | Redeem code already used, disabled or expired | Contact us |
| 413 | Speech recognition upload over 25 MB | Compress or split the file and upload again |
| 429 | Rate, concurrency or daily quota exceeded, or the model is at capacity | Wait for Retry-After, then retry |
| 500 | Unexpected server error | Retry once; if it persists, contact us |
| 502 | Model backend unreachable (All replicas failed) | Retry with exponential backoff; if it keeps failing, check the service status or switch models |
| 503 | Model under maintenance or being switched | Wait 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.
| Order | Check | On failure |
|---|---|---|
| 1 | Is the key valid? | 401 |
| 2 | Is the request valid JSON? | 400 |
| 3 | Is the key allowed to use this endpoint and model? | 403 |
| 4 | Does the model exist and is it available? | 404 |
| 5 | Is the model under maintenance or being switched? | 503 |
| 6 | Concurrent in-flight requests for the key | 429 |
| 7 | Prepaid balance | 402 |
| 8 | Requests per minute | 429 |
| 9 | Daily token quota | 429 |
| 10 | Overall model capacity | 429 |
| 11 | Model backend processing | 400 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
- Retry only 429, 502 and 503, plus network-level connection errors.
- 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. - 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.
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
messagesto 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.jsonregularly 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/subscriptionregularly 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
| Method | Path | Purpose | Key required |
|---|---|---|---|
| GET | /v1/models | List the models and prices available to your key | Yes |
| POST | /v1/chat/completions | Chat, tool calling, image input | Yes |
| POST | /v1/completions | Text completions | Yes |
| POST | /v1/embeddings | Text embeddings | Yes |
| POST | /v1/rerank | Document reranking | Yes |
| POST | /v1/images/generations, /v1/images | Image generation | Yes |
| POST | /v1/audio/speech | Text to speech | Yes |
| POST | /v1/audio/transcriptions | Speech recognition | Yes |
| POST | /v1/videos | Submit a video generation job | Yes |
| GET | /v1/videos/{id} | Check a video job | Yes |
| GET | /v1/videos/{id}/content | Download the video (MP4) | Yes |
| DELETE | /v1/videos/{id} | Cancel a queued video job | Yes |
| GET | /v1/personas/{persona_id} | Read a persona | Yes |
| POST | /v1/redeem | Redeem a credit code | Yes |
| GET | /dashboard/billing/subscription | Check balance | Yes |
| GET | /dashboard/billing/usage | Check cumulative usage | Yes |
| GET | https://b300.powerchampion.ai/status.json | Live model status | No |
| GET | https://b300.powerchampion.ai/catalog.json | Public model catalog and list prices | No |
| GET | https://b300.powerchampion.ai/health | Gateway liveness check | No |
B. Not currently supported
- OpenAI Responses API, Assistants, Files, Batches, Moderations.
- Audio translation
/v1/audio/translationsand 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
| Item | Where |
|---|---|
| Service status page | powerchampion.ai/status |
| Online developer docs | powerchampion.ai/docs/api |
| Terms of Service | powerchampion.ai/terms |
| Technical support and billing | info@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
| Date | Version | Changes |
|---|---|---|
| 2026-10-20 | 1.0 | First release, covering the endpoints and models in sections 1–12. |