Skip to content

tokenexplore API Developer Documentation ​

TIP

The help center has been split into multiple pages: for day-to-day use, start from the help center home and open the topic-specific docs (LLM API, image generation, video generation, clients, and CLI). This file is kept as a complete single-page reference for full-text search.


Last updated: October 23, 2026

tokenexplore is an LLM API aggregation platform. All you need is one API Key to call Claude, Gemini, Kimi, DeepSeek, GLM, Qwen, Doubao Seedance, and other models through three compatible protocols: OpenAI / Anthropic (Claude) / Google Gemini.

Important

API Gateway Address

The API gateway address used in every example in this document is https://ai.afp.net (the same as in the console). If your environment uses a custom domain, use the address shown in the console.

Likewise, sk-xxxxxxxx only indicates the format of an API Key; replace it with a token you created yourself.


Table of Contents ​

  1. Quick Start
  2. Authentication
  3. Base URL and Compatible Protocols
  4. Model List
  5. OpenAI Chat Completions
  6. OpenAI Responses
  7. Anthropic Messages (Claude Native)
  8. Gemini Native API
  9. Streaming Output (SSE)
  10. Multimodal: Image Input
  11. Tool Calling (Function Calling)
  12. Reasoning / Thinking
  13. Image Generation
  14. Video Generation (Doubao Seedance)
  15. Embeddings
  16. SDK Examples Summary
  17. Common Client Setup
  18. Error Codes and Troubleshooting
  19. Tokens, Groups, and Rate Limits
  20. Billing
  21. FAQ

1. Quick Start ​

Four steps are all it takes to send your first request.

1.1 Sign Up and Log In ​

Open the tokenexplore console at https://ai.afp.net, then sign up and log in.

1.2 Top Up ​

Go to the "Wallet" or "Top Up" page and choose online payment, or redeem a code. Your balance is shown as "credits". For per-model pricing, see the "Model Plaza / Pricing" page in the console, and §20 Billing.

1.3 Create a Token (API Key) ​

  1. Go to "Token Management" and click "Add Token".
  2. Set the name, expiration time, credit limit, token group, available model scope, and IP allowlist as needed. If you are unsure, keep the defaults.
  3. After saving, click "Copy" to get a key that looks like sk-xxxxxxxxxxxxxxxx.

Warning

The API Key is your payment credential. Never put it in frontend code, mobile app packages, screenshots, logs, or public repositories. If you suspect it has leaked, delete or disable it in "Token Management" immediately and create a new one.

1.4 Send Your First Request ​

bash
export CIYUAN_BASE_URL="https://ai.afp.net"   # gateway address
export CIYUAN_API_KEY="sk-xxxxxxxx"                 # replace with your token

curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "Describe yourself in three sentences"}
    ]
  }'

choices[0].message.content in the returned JSON is the model's answer. The examples that follow assume you have already set the CIYUAN_BASE_URL and CIYUAN_API_KEY environment variables.

Python version:

python
# pip install -U openai
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["CIYUAN_API_KEY"],
    base_url=os.environ["CIYUAN_BASE_URL"] + "/v1",
)

resp = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "Describe yourself in three sentences"}],
)
print(resp.choices[0].message.content)

2. Authentication ​

All protocols share the same API Key; only the request header differs:

ProtocolRecommended headerAlternative
OpenAI compatible (/v1/chat/completions, /v1/responses, /v1/images/*, /v1/videos, etc.)Authorization: Bearer sk-xxx—
Anthropic Messages (/v1/messages)x-api-key: sk-xxx, plus anthropic-version: 2023-06-01Authorization: Bearer sk-xxx
Gemini native (/v1beta/models/...)x-goog-api-key: sk-xxxURL parameter ?key=sk-xxx, or Authorization: Bearer sk-xxx

Notes:

  • Each token can have its own credit limit, expiration time, available models, IP allowlist, and group. When any of these limits is triggered, the request is rejected; see §18.
  • The console session and the backend "system access token" are only for management endpoints (/api/*) and must not be used to call models. Use a token that starts with sk- to call models.

3. Base URL and Compatible Protocols ​

ProtocolMethod and pathUse case
OpenAI Chat CompletionsPOST https://ai.afp.net/v1/chat/completionsBest compatibility; recommended as the default. Works with every text model, and most third-party tools support only this endpoint
OpenAI ResponsesPOST https://ai.afp.net/v1/responsesThe new unified OpenAI endpoint. Availability depends on the model and channel; test before integrating
Anthropic MessagesPOST https://ai.afp.net/v1/messagesSuited to existing Anthropic SDK code, Claude Code, and similar. Recommended only for Claude-series models
Gemini generateContentPOST https://ai.afp.net/v1beta/models/{model}:generateContentSuited to existing Google GenAI SDK code, Gemini CLI, and Gemini image generation
Gemini streamingPOST https://ai.afp.net/v1beta/models/{model}:streamGenerateContent?alt=sseGemini native streaming output
Model listGET https://ai.afp.net/v1/modelsQuery the models available to the current token
Image generationPOST https://ai.afp.net/v1/images/generationsOpenAI image generation format
Video generation (video compatible protocol)POST https://ai.afp.net/v1/video/generations, GET https://ai.afp.net/v1/video/generations/{task_id}; the OpenAI Videos style POST /v1/videos is also supportedCompatible with existing OpenAI video tools; download results with GET /v1/videos/{task_id}/content
Video generation (Seedance official protocol)POST https://ai.afp.net/api/v3/contents/generations/tasksWhen you need the full feature set: all-modality references, 2.5 editing/extension, the assets library, signed callbacks, and more
Video assets library (official Assets API)POST https://ai.afp.net/api/v3/assets?Action=<Action>&Version=2024-01-01Import and manage reference image / video / audio assets
EmbeddingsPOST https://ai.afp.net/v1/embeddingsText vectorization; requires an embedding model available on the platform

How to Fill In the Base URL for Different Clients ​

Different SDKs and tools interpret "Base URL" differently. The three most common forms are:

FormTypically used by
https://ai.afp.netAnthropic SDK, Claude Code, Google GenAI SDK, Gemini CLI, Cherry Studio
https://ai.afp.net/v1Official OpenAI SDK (Python / Node), LobeChat, Cline (OpenAI Compatible), Cursor, LangChain
https://ai.afp.net/v1/chat/completionsA few tools that require the full endpoint URL

TIP

If one form returns 404, switch to the other two in turn. A single extra or missing /v1 will produce an incorrect path.

Can I Mix Models and Protocols? ​

Yes. The platform converts formats between protocols, so you can call Claude or Gemini through the OpenAI format, and you can call some non-Claude models through the Claude format. However, the conversion is not lossless for every field:

  • Claude series: prefer /v1/messages or /v1/chat/completions.
  • Gemini series: prefer /v1/chat/completions or the Gemini native API. For image generation, use the Gemini native API.
  • Kimi / DeepSeek / GLM / Qwen: use /v1/chat/completions.
  • Seedance video: only the video task endpoints work; see §14.

4. Model List ​

4.1 Query Endpoint ​

bash
curl "$CIYUAN_BASE_URL/v1/models" \
  -H "Authorization: Bearer $CIYUAN_API_KEY"

The response is an OpenAI-format list:

json
{
  "object": "list",
  "data": [
    {"id": "claude-sonnet-4-6", "object": "model", "owned_by": "..."},
    {"id": "gemini-3.1-pro", "object": "model", "owned_by": "..."}
  ]
}

The models returned are limited by the token's available model scope and the token's group. Treat the actual API response as authoritative.

When using the Gemini SDK, you can also query with the native format: GET https://ai.afp.net/v1beta/models (with the x-goog-api-key header).

4.2 Current Models at a Glance ​

Models are added and retired continuously, so the table below is only a snapshot as of the last update of this document. For pricing, refer to the "Model Plaza / Pricing" page in the console; this document does not list prices.

Claude (Anthropic) ​

Model IDDescription
claude-opus-5-5Opus-series flagship
claude-opus-5Opus 5
claude-opus-4-8Opus 4.8
claude-opus-4-7Opus 4.7
claude-opus-4-6Opus 4.6
claude-opus-4-6-thinkingOpus 4.6 with extended thinking enabled by default; see §12
claude-sonnet-5Sonnet 5
claude-sonnet-4-6Sonnet 4.6, recommended for everyday development
claude-sonnet-4-5-20250929Sonnet 4.5 (dated pinned version)
claude-haiku-4-5Haiku 4.5, low latency and low cost
claude-haiku-4-5-20251001Haiku 4.5 (dated pinned version)
claude-fable-5Fable 5
claude-fable-5-1Fable 5.1

Gemini (Google) ​

Model IDDescription
gemini-3.1-proGemini 3.1 Pro
gemini-3.1-pro-previewGemini 3.1 Pro preview
gemini-3.7-flashGemini 3.7 Flash
gemini-3.6-flashGemini 3.6 Flash
gemini-3.5-flashGemini 3.5 Flash
gemini-3.5-flash-liteGemini 3.5 Flash-Lite
gemini-3.1-flash-liteGemini 3.1 Flash-Lite
gemini-2.5-proGemini 2.5 Pro
gemini-2.5-flash-liteGemini 2.5 Flash-Lite
gemini-3-pro-imageImage generation / editing; see §13
gemini-3.1-flash-imageImage generation / editing (Flash tier)

Kimi (Moonshot AI) ​

Model IDDescription
kimi-k3Kimi K3
kimi-k3-usdA separate billing / channel variant of Kimi K3; see the console for details

DeepSeek ​

Model IDDescription
deepseek-v4-pro-0813DeepSeek V4 Pro
deepseek-v4-flashDeepSeek V4 Flash
deepseek-v4-1-flash-260910DeepSeek V4.1 Flash

GLM (Zhipu) ​

Model IDDescription
glm-5.3GLM-5.3
glm-5.3-flashGLM-5.3 Flash
glm-5.2GLM-5.2

Qwen (Tongyi) ​

Model IDDescription
qwen3.8-maxQwen3.8 Max
qwen3.8-flashQwen3.8 Flash

Doubao Seedance (Video Generation) ​

Model IDDescription
doubao-seedance-2-5-260628Seedance 2.5
doubao-seedance-2-0-260128Seedance 2.0 standard
doubao-seedance-2-0-fast-260128Seedance 2.0 Fast (faster, lower resolution cap)
doubao-seedance-2-0-mini-260615Seedance 2.0 Mini (lighter, lower resolution cap)

INFO

Not every model supports image input, tool calling, reasoning parameters, or /v1/responses. Before integrating for real, send one minimal request to the target model. The "Model Plaza" page in the console usually indicates which endpoint types each model supports.


5. OpenAI Chat Completions ​

POST https://ai.afp.net/v1/chat/completions

5.1 Basic Request ​

bash
curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [
      {"role": "system", "content": "You are a concise technical assistant."},
      {"role": "user", "content": "Explain what SSE is"}
    ],
    "temperature": 0.7,
    "max_tokens": 1024
  }'

5.2 Example Response ​

json
{
  "id": "chatcmpl-xxxx",
  "object": "chat.completion",
  "created": 1792000000,
  "model": "gemini-3.5-flash",
  "choices": [
    {
      "index": 0,
      "message": {"role": "assistant", "content": "SSE (Server-Sent Events) is ..."},
      "finish_reason": "stop"
    }
  ],
  "usage": {"prompt_tokens": 25, "completion_tokens": 180, "total_tokens": 205}
}

5.3 Common Fields ​

FieldDescription
modelRequired. Model ID.
messagesRequired. Array of chat messages; role can be system / user / assistant / tool.
streamWhether to enable streaming output; see §9.
stream_optionsWhen set to {"include_usage": true}, an extra chunk containing usage is returned before the stream ends.
max_tokens / max_completion_tokensMaximum number of output tokens. For reasoning models, the thinking process also consumes this budget.
temperature / top_pSampling parameters. Not supported by some reasoning models.
tools / tool_choiceTool calling; see §11.
response_formatStructured output, for example {"type": "json_object"}. Support depends on the model.
reasoning_effortReasoning effort: low / medium / high. Supported by only some models; see §12.
stop / seed / n / presence_penalty / frequency_penaltyStandard OpenAI parameters. Parameters unsupported upstream may be ignored or may raise an error.

5.4 Meaning of finish_reason ​

ValueMeaning
stopEnded normally
lengthHit the max_tokens limit. When a reasoning model returns empty content, this is usually why.
tool_callsThe model has requested a tool call
content_filterContent was filtered by a safety policy

6. OpenAI Responses ​

POST https://ai.afp.net/v1/responses

The platform supports the OpenAI Responses protocol. The request body uses input instead of messages, and instructions instead of a system message.

INFO

Responses is OpenAI's newer protocol. Whether a given model can be called through Responses depends on the channel the platform has configured for it. If you are calling a non-OpenAI model such as Claude, Gemini, or Kimi and have no particular reason to use Responses, prefer /v1/chat/completions or the vendor's native protocol. Run one minimal test with the target model before integrating; if it returns 4xx, switch back to Chat Completions.

bash
curl "$CIYUAN_BASE_URL/v1/responses" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "instructions": "You are a concise technical assistant.",
    "input": "Describe tokenexplore in three sentences",
    "max_output_tokens": 1024
  }'
python
resp = client.responses.create(
    model="claude-sonnet-4-6",
    input="Describe tokenexplore in three sentences",
)
print(resp.output_text)
FieldDescription
modelRequired
inputRequired. Can be a string or a structured message array.
instructionsSystem-level instructions
streamStreaming output; returns semantic SSE events such as response.output_text.delta
max_output_tokensMaximum number of output tokens
reasoningFor example {"effort": "high"}; depends on the model
toolsTool definitions (Responses format: fields are flat, not nested under function)

To determine whether the response finished, check the returned status. completed means it ended normally; incomplete means it stopped early, with the reason in incomplete_details.reason — a common value is max_output_tokens.


7. Anthropic Messages (Claude Native) ​

POST https://ai.afp.net/v1/messages

Suited to existing Anthropic SDK code, Claude Code, and various agent frameworks. The request body follows the Anthropic Messages API exactly.

bash
curl "$CIYUAN_BASE_URL/v1/messages" \
  -H "x-api-key: $CIYUAN_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 1024,
    "system": "You are a senior Go engineer.",
    "messages": [
      {"role": "user", "content": "How do you usually diagnose a goroutine leak?"}
    ]
  }'

Example response:

json
{
  "id": "msg_xxxx",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-4-8",
  "content": [{"type": "text", "text": "Diagnosing a goroutine leak starts with ..."}],
  "stop_reason": "end_turn",
  "usage": {"input_tokens": 30, "output_tokens": 420}
}

Key Differences Between the Anthropic and OpenAI Formats ​

ItemAnthropic MessagesOpenAI Chat Completions
max_tokensRequiredOptional
System promptTop-level system fieldA message with role: "system"
Images{"type":"image","source":{...}}{"type":"image_url","image_url":{...}}
Tool schemainput_schemafunction.parameters
Stop reasonstop_reason (end_turn / max_tokens / tool_use)finish_reason
Authenticationx-api-key + anthropic-versionAuthorization: Bearer

Prompt caching: if the model and channel support it, you can add "cache_control": {"type": "ephemeral"} to system or to a message block. On a cache hit, cache_read_input_tokens / cache_creation_input_tokens appear in usage, and billing changes accordingly; see §20.


8. Gemini Native API ​

The Base URL is https://ai.afp.net, and the paths match the Google Gemini API:

  • Non-streaming: POST https://ai.afp.net/v1beta/models/{model}:generateContent
  • Streaming: POST https://ai.afp.net/v1beta/models/{model}:streamGenerateContent?alt=sse
bash
curl "$CIYUAN_BASE_URL/v1beta/models/gemini-3.1-pro:generateContent" \
  -H "x-goog-api-key: $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemInstruction": {"parts": [{"text": "You are a concise assistant."}]},
    "contents": [
      {"role": "user", "parts": [{"text": "Why is seawater salty?"}]}
    ],
    "generationConfig": {"temperature": 0.7, "maxOutputTokens": 2048}
  }'

Python (Google GenAI SDK):

python
# pip install -U google-genai
import os
from google import genai
from google.genai import types

client = genai.Client(
    api_key=os.environ["CIYUAN_API_KEY"],
    http_options=types.HttpOptions(base_url=os.environ["CIYUAN_BASE_URL"]),
)

resp = client.models.generate_content(
    model="gemini-3.1-pro",
    contents="Why is seawater salty?",
)
print(resp.text)

INFO

The platform does not currently support :countTokens; calls return 404. To estimate tokens, refer to usageMetadata in the response.


9. Streaming Output (SSE) ​

With stream: true, the endpoint returns a Server-Sent Events stream instead of a single complete JSON document. The client must read events starting with data: line by line.

9.1 OpenAI Chat Completions Streaming ​

bash
curl -N "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-flash",
    "stream": true,
    "stream_options": {"include_usage": true},
    "messages": [{"role": "user", "content": "Write a short poem about autumn"}]
  }'

Event format:

text
data: {"id":"chatcmpl-xxx","choices":[{"index":0,"delta":{"role":"assistant","content":"Aut"}}]}

data: {"id":"chatcmpl-xxx","choices":[{"index":0,"delta":{"content":"umn"}}]}

data: {"id":"chatcmpl-xxx","choices":[],"usage":{"prompt_tokens":20,"completion_tokens":28,"total_tokens":48}}

data: [DONE]

Python:

python
stream = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[{"role": "user", "content": "Write a short poem about autumn"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:  # final chunk
        print("\nUsage:", chunk.usage)

Node.js:

javascript
const stream = await client.chat.completions.create({
  model: "deepseek-v4-flash",
  messages: [{ role: "user", content: "Write a short poem about autumn" }],
  stream: true,
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

9.2 Anthropic Streaming ​

Add "stream": true to the /v1/messages request body to receive the standard Anthropic events: message_start → content_block_start → multiple content_block_delta → content_block_stop → message_delta → message_stop. Reading them with the SDK is the easiest approach:

python
with claude.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Tell a programmer joke"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

9.3 Gemini Streaming ​

Use :streamGenerateContent?alt=sse. Each data: payload is a partial GenerateContentResponse.

9.4 Notes ​

  • Pass -N to curl to disable buffering.
  • Reverse proxies such as Nginx must have buffering disabled (proxy_buffering off;), otherwise output is accumulated and flushed all at once.
  • During long reasoning runs, the stream may have no body text for a while. Set the client read timeout generously — at least 300 seconds is recommended.

10. Multimodal: Image Input ​

This section is about letting a model look at images, understand them, and extract text from them. To generate images, see §13.

The models that support image input are mainly the Claude and Gemini series (excluding the *-image generation models). For whether models such as Kimi, Qwen, and GLM support visual input, refer to the labels in Model Plaza.

The image field differs across the three protocols:

ProtocolHow to write it
Chat CompletionsIn messages[].content[], use {"type":"image_url","image_url":{"url":"..."}}
ResponsesIn input[].content[], use {"type":"input_image","image_url":"..."}
Anthropic MessagesIn messages[].content[], use {"type":"image","source":{...}}
Gemini nativeIn parts[], use {"inlineData":{"mimeType":"image/png","data":"<base64>"}}

10.1 Chat Completions ​

bash
curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "Describe this image and extract the text in it"},
        {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}}
      ]
    }]
  }'

You can also pass a local image as a Base64 Data URL:

json
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,BASE64_IMAGE_DATA"}}

Reading a local image in Python:

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

resp = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What is in this picture?"},
            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
        ],
    }],
)

10.2 Anthropic Messages ​

json
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "messages": [{
    "role": "user",
    "content": [
      {"type": "text", "text": "Describe this image"},
      {"type": "image", "source": {"type": "url", "url": "https://example.com/image.png"}}
    ]
  }]
}

Base64 form:

json
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "BASE64_IMAGE_DATA"}}

10.3 Image Input Troubleshooting ​

  • First confirm that the model supports visual input.
  • The image URL must be directly reachable from the public internet, without a login or hotlink protection. If unsure, switch to a Data URL.
  • An image that is too large can exceed the request body limit (413) or increase costs; compress it to a long edge of no more than 2000px first.

11. Tool Calling (Function Calling) ​

11.1 OpenAI Format (Complete Round Trip) ​

python
import json

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a specified city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name, for example Beijing"}
            },
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "What is the weather in Beijing right now?"}]

# First round: the model decides to call a tool
resp = client.chat.completions.create(
    model="claude-sonnet-4-6", messages=messages, tools=tools, tool_choice="auto"
)
msg = resp.choices[0].message
messages.append(msg)

if msg.tool_calls:
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = {"city": args["city"], "weather": "sunny", "temp_c": 18}  # replace with your real implementation
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result, ensure_ascii=False),
        })

    # Second round: hand the tool results to the model to produce the final answer
    final = client.chat.completions.create(
        model="claude-sonnet-4-6", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)

Possible values for tool_choice: "auto" (default), "none", "required", or {"type":"function","function":{"name":"get_weather"}} (force a call to a specific function).

11.2 Anthropic Format ​

bash
curl "$CIYUAN_BASE_URL/v1/messages" \
  -H "x-api-key: $CIYUAN_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 1024,
    "tools": [{
      "name": "get_weather",
      "description": "Get the current weather for a specified city",
      "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
      }
    }],
    "messages": [{"role": "user", "content": "What is the weather in Beijing right now?"}]
  }'

When the response has stop_reason: "tool_use", take the type: "tool_use" block from content (it contains id, name, and input). After running the tool, send the result back in a user message in the next round:

json
{"role": "user", "content": [
  {"type": "tool_result", "tool_use_id": "toolu_xxx", "content": "{\"weather\":\"sunny\",\"temp_c\":18}"}
]}

11.3 Tips ​

  • Tool calling support varies by model. The flagship models of Claude, Gemini, Kimi, DeepSeek, GLM, and Qwen generally support it.
  • parameters / input_schema must be a valid JSON Schema. When there are no parameters, write {"type":"object","properties":{}}.
  • With parallel tool calls, tool_calls may contain several calls at once, and each result must be sent back individually.

12. Reasoning / Thinking ​

Reasoning models think before they answer. The thinking process consumes tokens, is generally billed as output, and counts against the max_tokens budget.

12.1 Claude Extended Thinking ​

Option 1: Native Anthropic parameters (recommended)

json
{
  "model": "claude-opus-4-8",
  "max_tokens": 16000,
  "thinking": {"type": "enabled", "budget_tokens": 8000},
  "messages": [{"role": "user", "content": "Prove that the square root of 2 is irrational"}]
}
  • budget_tokens must be less than max_tokens and no less than 1024.
  • The returned content first contains a type: "thinking" block, followed by a type: "text" block.
  • Once thinking is enabled, do not set sampling parameters such as temperature or top_k.

Option 2: Use a -thinking model directly

claude-opus-4-6-thinking has thinking enabled by default and can be called through any protocol.

bash
curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-4-6-thinking",
    "max_tokens": 16000,
    "messages": [{"role": "user", "content": "Prove that the square root of 2 is irrational"}]
  }'

When calling through Chat Completions, the thinking content is generally placed in choices[0].message.reasoning_content, and in delta.reasoning_content when streaming. The answer itself is still in content.

12.2 Gemini Thinking ​

The Gemini 2.5 / 3.x series think by default.

  • Chat Completions: you can pass "reasoning_effort": "low" | "medium" | "high", and the platform converts it into Gemini's thinking configuration. The exact mapping depends on the model.
  • Gemini native: control it through generationConfig.thinkingConfig:
json
{
  "contents": [{"role": "user", "parts": [{"text": "Calculate 37 × 43 step by step"}]}],
  "generationConfig": {
    "thinkingConfig": {"thinkingBudget": 2048, "includeThoughts": true}
  }
}

The Gemini 3 series also supports "thinkingLevel": "low" | "high". The supported fields are determined by Google's official documentation and the actual response.

12.3 DeepSeek / Kimi / GLM / Qwen ​

These models are called through /v1/chat/completions. If the model has a thinking process, it is generally returned in the reasoning_content field. Whether reasoning_effort or parameters that toggle thinking are supported depends on each model's documentation.

12.4 Common Pitfalls with Reasoning Models ​

  • Empty content: most likely max_tokens was set too low and the entire budget was consumed by the thinking process, in which case finish_reason is length. Increase max_tokens or drop the parameter.
  • Parameter errors: reasoning models are stricter about parameters such as temperature, top_p, presence_penalty, frequency_penalty, and logprobs. If you get an error, remove these sampling parameters first and keep only the model, messages, and token limit.
  • Slow first token: thinking takes time. A non-streaming request waits until thinking finishes before returning; use streaming where responsiveness matters.

13. Image Generation ​

gemini-3-pro-image and gemini-3.1-flash-image are both Gemini native "text + image" multimodal output models. Calling them through the native Gemini generateContent is recommended:

bash
curl "$CIYUAN_BASE_URL/v1beta/models/gemini-3-pro-image:generateContent" \
  -H "x-goog-api-key: $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [{"role": "user", "parts": [{"text": "An orange tabby cat sitting by the window watching the rain, watercolor style"}]}],
    "generationConfig": {
      "responseModalities": ["TEXT", "IMAGE"],
      "imageConfig": {"aspectRatio": "16:9"}
    }
  }'

In the returned candidates[0].content.parts[], the part carrying inlineData (mimeType + Base64 data) is the image. Python example:

python
import base64
from google.genai import types

resp = client.models.generate_content(
    model="gemini-3-pro-image",
    contents="An orange tabby cat sitting by the window watching the rain, watercolor style",
    config=types.GenerateContentConfig(response_modalities=["TEXT", "IMAGE"]),
)
for part in resp.candidates[0].content.parts:
    if part.inline_data:
        with open("cat.png", "wb") as f:
            f.write(part.inline_data.data)  # the SDK has already decoded the Base64
    elif part.text:
        print(part.text)

Image editing / reference images: put an inlineData image and a text instruction in parts together (for example, "change the background to a snowy scene").

INFO

You can also call these two models through /v1/chat/completions, but the form in which the generated image appears in content (for example, a Markdown image or a Data URL) depends on the platform version and channel configuration. For batch production, use the native API.

13.2 OpenAI Images API ​

The platform also provides OpenAI-format image endpoints:

  • Generation: POST https://ai.afp.net/v1/images/generations
  • Editing: POST https://ai.afp.net/v1/images/edits (multipart/form-data or JSON)
bash
curl "$CIYUAN_BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<a model marked in the console as supporting images/generations>",
    "prompt": "An orange tabby cat sitting by the window watching the rain, watercolor style",
    "n": 1,
    "size": "1024x1024",
    "response_format": "b64_json"
  }'

The images API waits synchronously for generation within the request, and the result is returned only in that response; it cannot be queried afterwards, so save it promptly. If it takes too long, it may return 504 task_timeout. Which models can be used with this endpoint depends on the "supported endpoints" labels in Model Plaza.


14. Video Generation (Doubao Seedance) ​

Video generation is an asynchronous task: submit a task, get the task ID, poll the task status, and download the video when it is done. Task IDs are assigned centrally by the platform, and queries must use the account that owns the token.

The platform offers two integration protocols. They share the same API Key, account credits, and billing system, but their request fields, response structures, and status enums differ. Use the same protocol for creation, querying, and status checks:

ProtocolCreateQueryDownloadUse case
Video compatible protocolPOST /v1/video/generations (the OpenAI Videos style POST /v1/videos is also supported)GET /v1/video/generations/{task_id} (use GET /v1/videos/{id} for the OpenAI Videos style)GET /v1/videos/{task_id}/contentExisting OpenAI video clients that only need text-to-video or image-to-video
Seedance official protocolPOST /api/v3/contents/generations/tasksGET /api/v3/contents/generations/tasks/{task_id}content.video_url, or GET /v1/videos/{task_id}/contentAll-modality references, 2.5 editing/extension, the assets library, signed callbacks

Only the OpenAI Videos style endpoint uses queued / in_progress / completed / failed, where completed corresponds to succeeded in the Seedance official protocol; queries on the legacy compatible endpoint return the platform's internal states (such as IN_PROGRESS / SUCCESS / FAILURE). Do not mix endpoints and response structures from the two protocols.

There is also the assets library (official Assets API): POST https://ai.afp.net/api/v3/assets?Action=<Action>&Version=2024-01-01, used to import and manage reference images / videos / audio and to reference them in the official protocol with asset://<asset ID>. See §14.3 and Video Generation · Assets Library for details.

14.1 Video Compatible Protocol ​

Submit a task

bash
curl "$CIYUAN_BASE_URL/v1/video/generations" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2-5-260628",
    "prompt": "Sunrise by the sea, the camera slowly pushes in, waves lapping against the rocks, cinematic",
    "seconds": "4",
    "metadata": {
      "resolution": "480p",
      "ratio": "16:9",
      "generate_audio": false
    }
  }'

A successful creation only means the task has been accepted; no video URL is returned. The legacy compatible endpoint returns:

json
{"id": "task_xxxxxxxxx", "task_id": "task_xxxxxxxxx", "status": "queued", "model": "doubao-seedance-2-5-260628", "created_at": 1787827200}

The OpenAI Videos style endpoint (POST /v1/videos) returns a video object (without task_id):

json
{"id": "task_xxxxxxxxx", "object": "video", "model": "doubao-seedance-2-5-260628", "status": "queued", "progress": 0, "created_at": 1787827200}

Request parameters

FieldDescription
modelRequired. Seedance model ID.
promptRequired. The prompt.
imagesArray of reference image URLs. The OpenAI Videos style path accepts only images; do not pass a single image.
imageSingle image URL supported by the legacy compatible endpoint (converted to images internally); new code should use images consistently.
secondsDuration as a string, such as "4" or "-1". Takes precedence when duration is also present.
durationDuration as an integer. It can replace seconds on the OpenAI Videos style endpoint; the legacy compatible endpoint reads only seconds and ignores duration.
metadataPass-through official parameters: content, resolution, ratio, generate_audio, omni_reference_task_type, and so on.

Parameters such as resolution, ratio, and generate_audio must be placed inside metadata; at the top level they are ignored. Put reference images/videos/audio in metadata.content, and always write the prompt in prompt.

Query a task

GET /v1/videos/{task_id} returns an OpenAI Video object with the status queued → in_progress → completed (or failed); the response does not contain a video URL:

bash
curl "$CIYUAN_BASE_URL/v1/videos/task_xxxxxxxxx" \
  -H "Authorization: Bearer $CIYUAN_API_KEY"

GET /v1/video/generations/{task_id} returns the generic task structure, with the result URL in data.result_url (the field may be absent; the download endpoint is authoritative):

bash
curl "$CIYUAN_BASE_URL/v1/video/generations/task_xxxxxxxxx" \
  -H "Authorization: Bearer $CIYUAN_API_KEY"
json
{"code": "success", "message": "", "data": {"task_id": "task_xxxxxxxxx", "status": "IN_PROGRESS", "progress": "60%"}}

The /v1/videos/{id} response has no metadata.url, task_id, or video URL. Always download results with GET /v1/videos/{task_id}/content.

Download the video (after the task completes)

bash
curl -L "$CIYUAN_BASE_URL/v1/videos/<task_id>/content" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -o output.mp4

The download endpoint supports the Range request header, so segmented downloads and resumable transfers are possible.

14.2 Seedance Official Protocol (Most Complete Parameters) ​

Submit a task

bash
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-20261023-001" \
  -d '{
    "model": "doubao-seedance-2-5-260628",
    "content": [
      {"type": "text", "text": "A little girl running through a wheat field, wind stirring the wheat, backlit by the setting sun"},
      {"type": "image_url", "image_url": {"url": "https://example.com/first_frame.png"}, "role": "first_frame"}
    ],
    "duration": 4,
    "resolution": "480p",
    "ratio": "16:9",
    "generate_audio": false
  }'

The response is the public task ID:

json
{"id": "task_xxxxxxxxx"}

Query a task

bash
curl "$CIYUAN_BASE_URL/api/v3/contents/generations/tasks/task_xxxxxxxxx" \
  -H "Authorization: Bearer $CIYUAN_API_KEY"
json
{
  "id": "task_xxxxxxxxx",
  "model": "doubao-seedance-2-5-260628",
  "status": "succeeded",
  "content": {"video_url": "https://example.com/result.mp4", "video_asset_id": "asset_xxxxxxxxx"},
  "usage": {"completion_tokens": 38830, "total_tokens": 38830},
  "created_at": 1787827200,
  "updated_at": 1787827300
}

The statuses are queued, running, succeeded, failed, cancelled, and expired. On failure, error contains code and message; the final charge is settled on usage.total_tokens, and failed tasks are refunded asynchronously after backend confirmation. When result archiving is enabled on the platform, a successful response may also contain content.video_asset_id.

Common parameters

FieldDescription
modelRequired. Seedance model ID; see §4.2.
contentRequired. An ordered array. Element types can be text (prompt), image_url (reference image / first frame / last frame, distinguished by role: first_frame / last_frame / reference_image), video_url (reference_video), audio_url (reference_audio), or draft_task.
duration2.0: -1 or 4–15; 2.5: -1 or 4–30
resolutionFor example 480p / 720p / 1080p. 2.0 Fast and 2.0 Mini max out at 720p; the standard and 2.5 versions support higher resolutions — refer to the model documentation for specifics.
ratio16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptive
generate_audioWhether to generate audio as well (depends on the model)
omni_reference_task_type2.5 only: auto / reference / edit / extend; edit requires reference_video, ratio=adaptive, and duration=-1
callback_urlCallback address for the task's final state; requires the platform's callback capability to be enabled and must be a public http(s) URL.
return_last_frameReturn the last frame; when result archiving is enabled on the platform, last_frame_url / last_frame_asset_id may appear in a successful response.
execution_expires_afterTask execution expiry in seconds, range 3600–259200
seed / camera_fixed / watermark / draft / frames / tools / output_format / service_tier / priorityAdvanced parameters; whether they take effect depends on the model and channel.

The official protocol uses an ordered content array to describe the prompt and reference assets, and you can integrate by changing only the Base URL of the Volcengine Ark SDK. For the complete parameter set, 2.5 editing examples, and signed callbacks, see Video Generation · Seedance Official Protocol.

14.3 Assets Library (Assets API) ​

The assets library uses the Action-style endpoint: POST https://ai.afp.net/api/v3/assets?Action=<Action>&Version=2024-01-01. Version must be 2024-01-01; the outer response layer is ResponseMetadata, business data is in Result, and errors are in ResponseMetadata.Error.

CategoryActions
GroupsCreateAssetGroup, ListAssetGroups, GetAssetGroup, UpdateAssetGroup, DeleteAssetGroup
AssetsCreateAsset, ListAssets, GetAsset, UpdateAsset, DeleteAsset
Real-person verificationCreateVisualValidateSession, GetVisualValidateResult (returns CapabilityNotSupported when all parameters are valid)
  • CreateAsset requires GroupId, Name, AssetType (Image / Video / Audio), and a public URL; AssetType must match the actual media type of the URL.
  • Assets and groups are isolated by user + ProjectName; assets are retained for 7 days by default (configurable for long-term retention).
  • After import, reference an asset in the official protocol's content with asset://<asset ID>; the platform's asset reference capability must be enabled.
  • Pagination: MaxResults (default 10, maximum 100) + NextToken; PageNumber + PageSize is also supported (PageNumber × PageSize limits: 20,000 for assets and 10,000 for groups; exceeding them returns InvalidParameter.Pagination).
  • The console and internal tools also use REST endpoints (/api/v3/assets, /api/media/assets, etc.) to manage assets; the Action endpoint is better suited to programmatic integration.

For complete examples, retention periods, and error codes, see Video Generation · Assets Library.

14.4 Python Polling Example (OpenAI Videos Style) ​

python
import os, time, requests

BASE = os.environ["CIYUAN_BASE_URL"]
H = {"Authorization": f"Bearer {os.environ['CIYUAN_API_KEY']}"}

task = requests.post(f"{BASE}/v1/videos", headers=H, json={
    "model": "doubao-seedance-2-0-mini-260615",
    "prompt": "A Shiba Inu rolling in the snow, slow motion",
    "seconds": "4",
    "metadata": {"resolution": "720p", "ratio": "16:9"},
}).json()
task_id = task["id"]
print("Task submitted:", task_id)

while True:
    info = requests.get(f"{BASE}/v1/videos/{task_id}", headers=H).json()
    status = info.get("status")
    print("Status:", status, info.get("progress", ""))
    if status == "completed":
        break
    if status == "failed":
        raise RuntimeError(info.get("error"))
    time.sleep(10)

with requests.get(f"{BASE}/v1/videos/{task_id}/content", headers=H, stream=True) as r:
    r.raise_for_status()
    with open("output.mp4", "wb") as f:
        for chunk in r.iter_content(1 << 20):
            f.write(chunk)
print("Saved output.mp4")

14.5 Notes on Video Tasks ​

  • Video generation usually takes tens of seconds to several minutes. A polling interval of 5–15 seconds is recommended; do not poll at high frequency.
  • Video links returned upstream generally expire, so download or re-host them as soon as possible. Alternatively, download through the /v1/videos/{task_id}/content proxy for consistency.
  • Field mapping for the video compatible protocol is handled by a platform plugin. When you need first/last frames, reference video/audio, 2.5 editing/extension, the assets library, or signed callbacks, switch to the Seedance official protocol.
  • Video is billed per generation or per second and may vary with resolution, duration, and whether audio is generated; see the pricing page in the console for details.
  • For production systems, save task_xxx, the model, key parameters, and error information. With the official protocol, send an Idempotency-Key to avoid duplicate tasks and duplicate charges caused by client retries.

15. Embeddings ​

POST https://ai.afp.net/v1/embeddings (OpenAI format); the Gemini native format is :embedContent / :batchEmbedContents.

bash
curl "$CIYUAN_BASE_URL/v1/embeddings" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "<embedding model ID>", "input": ["tokenexplore", "LLM API aggregation"]}'

INFO

The current model list does not yet include a dedicated embedding model. The endpoint itself is usable and can be called once an embedding model is available on the platform. Refer to the /v1/models response.


16. SDK Examples Summary ​

16.1 Python · OpenAI SDK ​

python
# pip install -U openai
from openai import OpenAI

client = OpenAI(api_key="sk-xxxxxxxx", base_url="https://ai.afp.net/v1")

resp = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

16.2 Node.js / TypeScript · OpenAI SDK ​

javascript
// npm i openai
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.CIYUAN_API_KEY,
  baseURL: `${process.env.CIYUAN_BASE_URL}/v1`,
});

const resp = await client.chat.completions.create({
  model: "glm-5.3",
  messages: [{ role: "user", content: "Hello" }],
});
console.log(resp.choices[0].message.content);

16.3 Python · Anthropic SDK ​

python
# pip install -U anthropic
import anthropic

claude = anthropic.Anthropic(
    api_key="sk-xxxxxxxx",
    base_url="https://ai.afp.net",   # Note: do not include /v1; the SDK appends /v1/messages automatically
)

msg = claude.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
print(msg.content[0].text)

16.4 Node.js · Anthropic SDK ​

javascript
// npm i @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";

const claude = new Anthropic({
  apiKey: process.env.CIYUAN_API_KEY,
  baseURL: process.env.CIYUAN_BASE_URL, // no /v1
});

const msg = await claude.messages.create({
  model: "claude-haiku-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Hello" }],
});
console.log(msg.content[0].text);

16.5 Python · Google GenAI SDK ​

See §8. The key point is http_options=types.HttpOptions(base_url="https://ai.afp.net"), without /v1beta after it.

16.6 LangChain ​

python
# pip install -U langchain-openai
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="qwen3.8-max",
    api_key="sk-xxxxxxxx",
    base_url="https://ai.afp.net/v1",
)
print(llm.invoke("Hello").content)

16.7 Environment Variables ​

Many tools read the following environment variables automatically:

bash
# OpenAI ecosystem
export OPENAI_API_KEY="sk-xxxxxxxx"
export OPENAI_BASE_URL="https://ai.afp.net/v1"

# Anthropic ecosystem
export ANTHROPIC_API_KEY="sk-xxxxxxxx"
export ANTHROPIC_BASE_URL="https://ai.afp.net"

17. Common Client Setup ​

Where "API address" appears below, enter tokenexplore's real address, https://ai.afp.net; for "API Key", enter your sk- token.

17.1 Claude Code ​

bash
npm install -g @anthropic-ai/claude-code

Edit ~/.claude/settings.json (on Windows the path is %USERPROFILE%\.claude\settings.json):

json
{
  "env": {
    "ANTHROPIC_BASE_URL": "https://ai.afp.net",
    "ANTHROPIC_AUTH_TOKEN": "sk-xxxxxxxx",
    "ANTHROPIC_MODEL": "claude-sonnet-4-6",
    "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5",
    "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
  }
}

Then run claude in your project directory. You can also switch models inside a session with /model, for example claude-opus-4-8.

If you run into errors such as invalid beta flag, add the environment variable "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1".

17.2 Cherry Studio ​

  1. Open "Settings → Model Providers" and click "Add" at the bottom.
  2. Choose New API as the provider type (choose OpenAI if that option is not available).
  3. Set the API address to https://ai.afp.net and the API key to sk-xxxxxxxx.
  4. Click "Check" to test connectivity, then click "Manage" to fetch and select models.

If you want to use the native Claude protocol, add another provider of type Anthropic and use https://ai.afp.net as the API address as well.

17.3 Cursor ​

  1. Open "Settings → Models".
  2. Enter sk-xxxxxxxx under OpenAI API Key, turn on Override OpenAI Base URL, and enter https://ai.afp.net/v1.
  3. Click "Add model" and add model IDs manually, for example claude-sonnet-4-6, gemini-3.1-pro, or kimi-k3, then click Verify.

Cursor's requests are sent from Cursor's servers, so https://ai.afp.net must be reachable from the public internet. Some features, such as Tab completion, always use Cursor's own models and do not go through your custom key.

17.4 Cline / Roo Code (VS Code) ​

Option A: OpenAI Compatible

  • API Provider: OpenAI Compatible
  • Base URL: https://ai.afp.net/v1
  • API Key: sk-xxxxxxxx
  • Model ID: claude-sonnet-4-6 (or another model)

Option B: Anthropic (when using only Claude; natively supports prompt caching and thinking)

  • API Provider: Anthropic
  • Check "Use custom base URL" and enter https://ai.afp.net
  • API Key: sk-xxxxxxxx

17.5 LobeChat ​

"Settings → Language Models → OpenAI":

  1. API Key: sk-xxxxxxxx
  2. API proxy address: https://ai.afp.net/v1
  3. Click "Fetch model list", select the models you need, and save.

17.6 Gemini CLI ​

bash
npm install -g @google/gemini-cli

Add the following to ~/.gemini/.env or ~/.env:

env
GOOGLE_GEMINI_BASE_URL=https://ai.afp.net
GEMINI_API_KEY=sk-xxxxxxxx
GEMINI_MODEL=gemini-3.1-pro

Then run gemini.

17.7 Other OpenAI-Compatible Clients ​

Tools such as NextChat, Chatbox, ChatWise, Open WebUI, Dify, FastGPT, and Immersive Translate generally let you choose the "OpenAI / OpenAI compatible" provider type, then enter the Base URL and Key. For how to fill in the Base URL, see §3.


18. Error Codes and Troubleshooting ​

18.1 Error Response Format ​

OpenAI-compatible endpoints return the following on error:

json
{
  "error": {
    "message": "Error description",
    "type": "new_api_error",
    "code": "model_not_found",
    "param": ""
  }
}

The Anthropic and Gemini native endpoints try to return errors in their own protocol formats. When troubleshooting, record the complete error.message and the request ID from the response headers, if present.

18.2 HTTP Status Codes ​

Status codeMeaningCommon causes and handling
400Invalid request parametersMalformed JSON, a missing required field (such as max_tokens for Claude), or a parameter the model does not support. Remove optional parameters first and reproduce with a minimal request
401Authentication failedThe key is wrong, the Bearer prefix is missing, or the token was deleted or disabled. Check how the request header is written
403No permission or insufficient creditsInsufficient account balance, an exhausted or expired token credit limit, a token that is not allowed to use the model, or an IP outside the allowlist
404Path not foundThe Base URL has an extra or missing /v1, or the path is misspelled. It may also mean the endpoint is not supported by the platform (for example Gemini :countTokens)
413Request body too largeThe image or text is too large; compress or split it
429Too many requestsThe platform or upstream rate limit was triggered; retry with exponential backoff, see §19
500Internal server errorRetry later. If it persists, contact support with the time and model
501Not implementedThe endpoint is not supported by the platform, such as /v1/files or /v1/fine-tunes
502 / 503Upstream unavailableThe upstream channel is failing, or there is no available channel for the model in the current group. Retry later or switch groups
504TimeoutGeneration took too long, for example synchronous image generation or long reasoning. Switch to streaming or asynchronous processing; an image task may still be running in the background

18.3 Typical Errors and Troubleshooting ​

Error keyword (example)CauseSolution
无效的令牌 / invalid tokenThe key is wrong or has been deletedCopy the key again and check for extra spaces
额度不足 / quota / insufficientInsufficient account balance or token creditsTop up, or raise the token's credit limit
当前分组 xxx 下对于模型 xxx 无可用渠道 / model_not_foundThe model name is misspelled, or the token's group does not have this modelVerify the model name with /v1/models, or switch groups in the token settings
该令牌无权使用模型The token has an "available models" restrictionEdit the token and allow the model
Related to max_tokensClaude is missing max_tokens, or thinking's budget_tokens ≥ max_tokensAdd the parameter, or increase max_tokens
Empty content with finish_reason: lengthThe reasoning model spent the token budget on thinkingIncrease max_tokens
Streaming output arrives all at onceThe proxy or gateway buffersDisable reverse proxy buffering; add -N to curl

18.4 Troubleshooting Checklist ​

  1. First verify the key and Base URL with the minimal curl request from §1.4 in this document.
  2. Use GET /v1/models to confirm that the model name matches exactly, paying attention to case and date suffixes.
  3. Remove all optional parameters, then add them back one by one to find the incompatible one.
  4. Check the model, usage, latency, and error information for that request in the console's "Usage Logs".
  5. When contacting support, provide: the time (with time zone), model, endpoint path, full error message, and request ID. Do not provide the full key.

19. Tokens, Groups, and Rate Limits ​

19.1 Token (API Key) Settings ​

SettingEffect
Expiration timeThe token stops working automatically after it expires
Credit limit / unlimited creditsCaps how much this token can spend; useful when distributing to team members or sub-projects
Available modelsOnly models on the allowlist can be called
IP allowlistOnly the specified IPs or subnets may use the token
Token groupDetermines which channel group requests use and which billing multiplier applies

We recommend creating a separate token for each application or environment and using credit limits to control risk.

19.2 Groups ​

The platform organizes available channels and billing multipliers into "groups" — for example, a default group, a high-availability group, or a discounted group. The console is authoritative.

  • Different groups may differ in price multiplier, stability, and available models.
  • A token can specify a group. If it does not, the account's default group is used.
  • If a model has no available channel in the current group, you get a "no available channel" error; switching groups resolves it.

19.3 Rate Limits ​

  • The platform may limit request rates by user, token, or model; upstream vendors also impose their own rate and concurrency limits.
  • When a limit is exceeded, the API returns 429. Retry with exponential backoff plus random jitter, for example waiting 1s → 2s → 4s → 8s, for at most 5 attempts. Do not retry immediately and indefinitely.
  • For high-concurrency or large batch workloads, estimate usage first. If you need a higher quota, contact support to have it enabled.
python
import random, time
from openai import OpenAI, RateLimitError, APIStatusError

def chat_with_retry(client: OpenAI, max_retries: int = 5, **kwargs):
    for i in range(max_retries):
        try:
            return client.chat.completions.create(**kwargs)
        except RateLimitError:
            pass
        except APIStatusError as e:
            if e.status_code < 500:
                raise  # 4xx (other than 429) will not succeed on retry; re-raise
        time.sleep(2 ** i + random.random())
    raise RuntimeError("retry attempts exhausted")

The official OpenAI SDK retries automatically; configure the count and timeout with OpenAI(max_retries=3, timeout=600).

19.4 Usage Queries ​

  • Console: "Usage Logs" shows the model, token usage, charges, and latency of each request; the "Dashboard" shows consumption trends.
  • API: call GET https://ai.afp.net/api/usage/token/ with a model token (header Authorization: Bearer sk-xxx) to query that token's credit usage.

20. Billing ​

This document does not list specific prices. All prices are subject to the real-time data on the console's "Model Plaza / Pricing" page.

20.1 Billing Modes ​

ModeTypically used forDescription
Usage-based (token) billingText chat, reasoning, vision understandingInput and output tokens are priced separately; output usually costs more per token
Per-request billingSome image / video modelsA fixed amount of credits is charged for each successful request
Per-second / per-spec billingVideo generationDepends on duration, resolution, whether audio is generated, and other parameters

20.2 Factors That Affect Cost ​

  • Model unit price: prices vary widely between models. Flash / Lite / Haiku models are much cheaper than Pro / Opus models.
  • Group multiplier: different groups have different multipliers; see §19.2.
  • Caching: input tokens that hit the prompt cache usually get a discount. Writing to the cache (Claude) may be billed at a higher multiplier.
  • Reasoning tokens: the thinking process is generally billed as output tokens.
  • Multimodal input: images are converted to tokens for billing, and larger images consume more.

20.3 Deduction Flow ​

  1. When a request starts, the platform reserves some credits based on the estimated usage.
  2. When the request finishes, it settles against the actual usage returned upstream, refunding or charging the difference.
  3. Failed requests (for example 4xx parameter errors or upstream errors) are generally not charged, or the reserved credits are returned. If a streaming request is interrupted midway, billing is based on the content already generated.

The charge details for every request can be found in "Usage Logs".

20.4 Money-Saving Tips ​

  • Use *-flash / *-lite / claude-haiku-4-5 for simple tasks, and Pro / Opus only for complex ones.
  • Keep the context short and trim history messages promptly.
  • For long, fixed system prompts, enable caching (add cache_control for Claude).
  • Set a reasonable upper bound for max_tokens to avoid runaway output.
  • Set credit limits on every token to limit the damage from a leaked key.

21. FAQ ​

Q: Should a new project use /v1/chat/completions or /v1/responses? A: On tokenexplore, prefer /v1/chat/completions, which has the best compatibility with all models. Use /v1/responses only after confirming that the target model supports Responses and that you genuinely need Responses features.

Q: Can I call Claude and Gemini with the OpenAI SDK? A: Yes. Just set model to a claude-* or gemini-* model, and the platform converts the protocol automatically. When you need features unique to Claude or Gemini (such as Claude's cache_control or Gemini's native image generation), use the native protocol.

Q: Why does the model's answer about "who are you" not match the model name? A: A model's sense of its own identity comes from its training data, which usually predates the model's release, so it may not know its official name. This does not mean you are calling the wrong model. If you need it to state its identity correctly, spell it out in the system prompt.

Q: The console shows a balance, so why does the API say credits are insufficient? A: Check whether the token's own credit limit has been exhausted. Account balance and token credits are two different things.

Q: Image input does not work? A: Confirm that the model supports visual input; that the image URL is publicly reachable (if unsure, switch to a Data URL); and that the field syntax matches the protocol (see §10). Do not pass image generation endpoint parameters to a chat endpoint.

Q: Why can't I JSON.parse a streaming response directly? A: A streaming response is an SSE event stream. Read the data: events line by line and parse each one separately, stopping at data: [DONE].

Q: I submitted a video task successfully, but the result never shows up? A: Video generation takes time, so keep polling patiently. If it stays in queued for a long time, upstream may be queuing. When it is failed, check error.message. Query with a token under the same account and use the task ID returned by the platform.

Q: What is the difference between claude-sonnet-4-5-20250929 and claude-sonnet-4-6? A: They are different model versions. A date suffix marks a pinned snapshot with more stable behavior, suitable for locking a version in production; a name without a date usually points to the recommended version of that series.

Q: Should I choose kimi-k3 or kimi-k3-usd? A: They are different billing or channel variants of the same model. Compare prices and descriptions on the console's pricing page before choosing.

Q: Are file uploads, fine-tuning, and Assistants supported? A: No. Endpoints such as /v1/files and /v1/fine-tunes return 501. To work with documents, extract their content as text or place it in a message as images.

Q: Is my data stored? A: The platform forwards requests and records the usage logs needed for billing (model, token counts, latency, and so on). For how data is handled, refer to the platform's Privacy Policy and Terms of Service.


Appendix: Endpoint Quick Reference ​

FeatureMethodPathAuthentication
Model listGET/v1/modelsBearer
Chat completionsPOST/v1/chat/completionsBearer
ResponsesPOST/v1/responsesBearer
Claude MessagesPOST/v1/messagesx-api-key / Bearer
Gemini generatePOST/v1beta/models/{model}:generateContentx-goog-api-key / ?key=
Gemini streamingPOST/v1beta/models/{model}:streamGenerateContent?alt=sseSame as above
Image generationPOST/v1/images/generationsBearer
Image editingPOST/v1/images/editsBearer
Video submit (video compatible)POST/v1/video/generationsBearer
Video query (video compatible)GET/v1/video/generations/{task_id}Bearer
Video submit (OpenAI Videos)POST/v1/videosBearer
Video query (OpenAI Videos)GET/v1/videos/{task_id}Bearer
Video downloadGET/v1/videos/{task_id}/contentBearer
Video submit (Seedance official)POST/api/v3/contents/generations/tasksBearer
Video query (Seedance official)GET/api/v3/contents/generations/tasks/{task_id}Bearer
Video task list (Seedance official)GET/api/v3/contents/generations/tasksBearer
Video task delete (Seedance official)DELETE/api/v3/contents/generations/tasks/{task_id}Bearer
Assets library (Action)POST/api/v3/assets?Action=<Action>&Version=2024-01-01Bearer
EmbeddingsPOST/v1/embeddingsBearer
Token usageGET/api/usage/token/Bearer (model token)

tokenexplore · If you have questions, contact support through the console.