Who this page is for
Start here if you want to connect an application, script, AI coding tool, or OpenAI-compatible client to Skypool Token. After reading this guide, you should be able to create a Consumer API Key and complete your first model call through the unified OpenAI-compatible API.
The caller-side flow for Skypool Token is simple:
- Use one unified
baseURL - Use a Consumer API Key as the Bearer Token
- Select a platform model with the request body's
modelfield - Use the OpenAI-compatible
/v1/chat/completionsendpoint for regular chat, streaming output, tool calls, and multimodal input - Review usage, status, failure reasons, and billing records in the console
API entry point
For production, set your OpenAI-compatible client's baseURL to:
https://a.skypool.xyz/v1The full chat endpoint is:
https://a.skypool.xyz/v1/chat/completionsAll OpenAI-compatible requests should carry the key in the request headers:
Authorization: Bearer <consumer_api_key>Do not put the API Key in URLs, logs, public frontend code, or configuration files that users can download.
Step 1: Create a Consumer API Key
Log in to the Skypool Token console, open the Consumer-side API Key page, and click Create API Key. After creation succeeds, the page displays the full key. Consumer keys usually start with stc-.
We recommend splitting keys by application or environment, for example:
| Scenario | Recommendation |
|---|---|
| Local development | Create a separate development key so it is easy to debug and delete at any time |
| Production service | Use a production key that is deployed only on the server side |
| AI coding tools | Create a separate key for each tool or team to make abnormal requests easier to troubleshoot |
| Temporary testing | Delete the key after testing to avoid leaving long-lived credentials behind |
Step 2: Choose a model
View currently available models on the Models page or in the usage examples in the console.
You can also read the model list through the OpenAI-compatible API:
https://a.skypool.xyz/v1/modelsContext length, pricing, tool-calling support, and multimodal capabilities may vary by model. Before connecting a production application, we recommend confirming the target model's response structure, latency, and failure semantics in the console or with a test script.
Step 3: Make your first request
The following is a minimal non-streaming request. Replace <consumer_api_key> with your Consumer API Key, and change model to the model you want to use.
For an even simpler test path, you can try it directly in Skypool Playground.
curl -X POST "https://a.skypool.xyz/v1/chat/completions" \ -H "Authorization: Bearer <consumer_api_key>" \ -H "Content-Type: application/json" \ --data-raw '{ "model": "qwen3.8:27b", "messages": [ { "role": "user", "content": "Hello, introduce Skypool Token in one sentence." } ], "max_tokens": 128, "stream": false }'If the response contains choices[0].message.content, your key, endpoint, and model are working.
Step 4: Enable streaming output
For interactive scenarios such as chat, agents, and AI coding tools, streaming output is recommended. Use stream: true for streaming requests, and include stream_options.include_usage: true so the final frame can return real usage.
curl -N -X POST "https://a.skypool.xyz/v1/chat/completions" \ -H "Authorization: Bearer <consumer_api_key>" \ -H "Content-Type: application/json" \ --data-raw '{ "model": "qwen3.8:27b", "messages": [ { "role": "user", "content": "Give me a minimal TypeScript HTTP client example." } ], "max_tokens": 512, "stream": true, "stream_options": { "include_usage": true } }'Streaming responses follow the OpenAI-compatible SSE format: each event starts with data:, and a normal completion returns data: [DONE]. Clients should handle incremental delta.content, tool-call deltas, the final usage frame, and mid-stream error events.
Session-level caching
For multi-turn conversations, Skypool Token automatically recognizes requests belonging to the same conversation and prefers the Provider node that last handled it successfully. This gives the inference runtime an opportunity to reuse previously computed context (KV cache), reducing repeated input processing and time to first token. You do not need to supply a session_id, custom session header, or prompt_cache_key to enable this automatic routing.
There are two parts: the platform tries to reuse a node, and the inference runtime on that node manages the actual cache. Reusing a node does not guarantee a cache hit or mean that the platform returns an earlier answer directly; each request still runs inference.
Keep a conversation consistent
For /v1/chat/completions, as used on this page, the platform identifies a conversation from the account, Consumer API Key, model, and the leading consecutive system / developer messages plus the first user message in messages. Appending messages after the first user does not change this identity.
- Continue using the same API Key and model for subsequent turns.
- Send the full conversation history each time. Preserve the initial system instructions and first user message, then append the actual model replies, tool results, and new questions in order. Automatic routing does not store or fill in message history for the client.
- Keep existing message contents and order stable. In particular, avoid repeatedly injecting changing timestamps or random values into the opening system instructions. Changing the opening messages, Key, or model changes the conversation identity.
- Under the same account, Key, and model, two conversations with identical openings share a node preference even if they are in different chat windows. This identity must therefore not be used as an application session ID or a data isolation mechanism.
For example, send this first turn:
{ "model": "qwen3.8:27b", "messages": [ { "role": "system", "content": "You are a TypeScript assistant. Answer concisely." }, { "role": "user", "content": "How do I set a timeout for an HTTP request?" } ], "max_tokens": 256, "stream": false}After receiving the reply, keep the original messages and append the next turn. The assistant.content below is illustrative; use the actual message returned by the first request in your application:
{ "model": "qwen3.8:27b", "messages": [ { "role": "system", "content": "You are a TypeScript assistant. Answer concisely." }, { "role": "user", "content": "How do I set a timeout for an HTTP request?" }, { "role": "assistant", "content": "Use AbortSignal.timeout to set a timeout for fetch." }, { "role": "user", "content": "Please also show how to handle timeout errors." } ], "max_tokens": 512, "stream": true, "stream_options": { "include_usage": true }}A successfully completed first turn establishes a node preference, which the second turn attempts to reuse. Within one conversation, wait for the previous turn to finish before sending the next. Keep system instructions, tool definitions, and history stable to improve the opportunity for context prefix reuse.
Expiration and node changes
The node preference expires after 15 minutes by default and is refreshed after each successfully completed request. The actual duration depends on platform configuration. This does not promise that the runtime will retain its KV cache for 15 minutes.
If the original node is offline, busy, lacks sufficient context capacity, or cannot satisfy the request's capabilities, the platform selects another available node through its normal routing rules. An expired preference also triggers a fresh selection. Node restarts, model reloads, runtime cache eviction, or input prefix changes can all cause a cache miss. Continue sending the full history after a node change so the cache can be rebuilt.
Confirm a cache hit
Use the cache token count actually reported by the inference runtime. The same node or a faster response alone is insufficient evidence. Cache-read usage fields differ by protocol, and their availability depends on the node runtime and its protocol support:
| Endpoint | Cache-read field in the response |
|---|---|
/v1/chat/completions | usage.prompt_tokens_details.cached_tokens |
/v1/responses | usage.input_tokens_details.cached_tokens |
/v1/messages | usage.cache_read_input_tokens |
For the Chat Completions streaming requests used on this page, include stream_options.include_usage: true and read the usage frame before the stream ends. For other protocols, read usage from their native responses or stream events. For example:
{ "usage": { "prompt_tokens": 1024, "prompt_tokens_details": { "cached_tokens": 768 }, "completion_tokens": 128, "total_tokens": 1152 }}Here, 768 of the 1024 input tokens were read from cache. Cached tokens are already included in the input total and must not be added again. A value greater than 0 reports a cache hit; 0 reports no hit. An absent field means no observable cache data was provided and must not be treated as 0.
Use Activity records to review the platform's recorded cached input and actual charges. Cached input is billed using the model pricing applied to that request. Conversation continuity or node reuse alone does not imply free input, a fixed discount, or a cache hit. Except for the temporary LM Studio billing rule below, input without reported cache usage is billed at the regular input price.
Temporary LM Studio billing rule: Because cache reporting for LM Studio's /v1/chat/completions protocol is incomplete, non-cached input is temporarily billed at the cached input price. This is a billing rule and does not indicate an actual cache hit. It applies only to LM Studio's /v1/chat/completions, not to /v1/responses, /v1/messages, or other runtimes.
Control Qwen3.8 reasoning consistently
Backend Relay provides reasoning parameter compatibility for qwen3.8:27b requests sent to /v1/chat/completions, /v1/responses, and /v1/messages. Each protocol uses its own native fields, so configure reasoning according to the selected protocol.
A platform-side rollout switch controls this layer: the off state does not parse or rewrite requests, the observe state only records the resolution, and the enforce state validates and converts parameters. This section describes enforce behavior for qwen3.8:27b. Consumer P2P direct requests must still follow the target runtime's own parameter conventions.
Chat Completions reasoning parameters
For /v1/chat/completions, use only the top-level reasoning_effort field in each request:
| Goal | Recommended parameter |
|---|---|
| Disable reasoning | "reasoning_effort": "none" |
| Enable low-effort reasoning | "reasoning_effort": "low" |
| Enable medium-effort reasoning | "reasoning_effort": "medium" |
| Enable maximum-effort reasoning | "reasoning_effort": "xhigh" |
For example, this request explicitly enables maximum-effort reasoning:
{ "model": "qwen3.8:27b", "messages": [ { "role": "user", "content": "Analyze the main risks in this proposal." } ], "reasoning_effort": "xhigh", "stream": true, "stream_options": { "include_usage": true }}For Chat Completions, the platform also recognizes these compatible forms:
| Compatible form | Supported switch fields |
|---|---|
| Top-level fields | think, enable_thinking, reasoning, thinking, reasoning_effort |
reasoning object | enabled, enable_thinking, effort, reasoning_effort, type, mode, status |
thinking object | enabled, enable_thinking, type, mode, status |
| Template arguments | chat_template_kwargs.enable_thinking, chat_template_kwargs.reasoning_effort |
The Chat Completions compatibility layer converts an explicit enable or disable intent into a consistent runtime parameter bundle. Keep these rules in mind:
- If the same request contains both enable and disable signals, disable wins to prevent unintended reasoning output.
- Both
reasoning_effort: "high"and"max"are mapped to the Qwen3.8-supported"xhigh". Preferlow,medium,xhigh, ornonedirectly;highandmaxremain available as compatibility aliases for maximum-effort reasoning. - If no explicit switch is provided, the compatibility layer does not inject reasoning parameters; the model and runtime defaults determine the final behavior.
include_reasoning,preserve_thinking, reasoning-content format fields, and reasoning budget fields are not generation switches and cannot enable or disable reasoning by themselves.
Responses reasoning parameters
/v1/responses uses the nested reasoning.effort field: low, medium, and xhigh select reasoning effort levels, while none disables reasoning. high / max are normalized to xhigh, and off is normalized to none.
{ "model": "qwen3.8:27b", "input": "Analyze the main risks in this proposal.", "reasoning": { "effort": "xhigh" }, "max_output_tokens": 1024, "store": false, "stream": true}The platform normalizes only reasoning.effort, preserving other native fields such as reasoning.summary. It does not inject Chat Completions fields such as reasoning_effort, think, or template parameters. Without reasoning.effort, the request remains unchanged; setting only reasoning.summary does not trigger the platform's reasoning-switch conversion.
Messages reasoning parameters
/v1/messages uses output_config.effort to specify reasoning effort. Prefer low, medium, or xhigh; high / max are normalized to xhigh. The native thinking configuration still expresses whether reasoning should be enabled or disabled, with support determined by the target runtime.
The following example uses Playground's native request format, requesting reasoning with thinking.type: "adaptive" and specifying the effort:
{ "model": "qwen3.8:27b", "messages": [ { "role": "user", "content": "Analyze the main risks in this proposal." } ], "thinking": { "type": "adaptive" }, "output_config": { "effort": "xhigh" }, "max_tokens": 1024, "stream": true}The platform normalizes only output_config.effort, preserving thinking.type, thinking.budget_tokens, output formats, and other native fields. It does not apply the Chat Completions rule that disable wins. To disable reasoning, use a native setting supported by the target runtime, such as "thinking": { "type": "disabled" }, and remove the enabling output_config.effort to avoid sending conflicting intent.
The platform does not interpret output_config.effort: "none" / "off" as a disable switch. Unrecognized native effort values in Responses and Messages are forwarded unchanged for the runtime to handle; do not assume these values work across runtimes.
Use the OpenAI SDK
Any OpenAI SDK or compatible client that supports a custom baseURL can connect directly to Skypool Token.
The example below supports switching between TypeScript and Python in the same code block and copying the code for the current language:
import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.SKYPOOL_API_KEY, baseURL: "https://a.skypool.xyz/v1",}); const completion = await client.chat.completions.create({ model: "qwen3.8:27b", messages: [ { role: "user", content: "Explain the benefit of an OpenAI-compatible API in one sentence.", }, ], max_tokens: 128,}); console.log(completion.choices[0]?.message?.content);Connect AI coding tools
When connecting an AI coding tool, choose a protocol supported by the tool, then configure the API Key, endpoint, and model. All three protocols use Skypool Token Consumer API Keys and platform model names:
| Configuration item | Value |
|---|---|
| API Key | Consumer API Key, for example stc-... |
| Base URL (OpenAI-style tools) | https://a.skypool.xyz/v1 |
| Model | Platform model name, for example qwen3.8:27b |
Choose a protocol and endpoint
| Protocol | Full endpoint (POST) | Protocol option in the tool |
|---|---|---|
| OpenAI-compatible protocol (Chat Completions) | https://a.skypool.xyz/v1/chat/completions | OpenAI Compatible / Chat Completions |
| OpenAI Responses protocol | https://a.skypool.xyz/v1/responses | OpenAI Responses / Responses API |
| Claude protocol (Messages) | https://a.skypool.xyz/v1/messages | Anthropic / Claude / Messages API |
Endpoint field names and path joining vary by tool. Ensure the final request URL matches the table above:
- If an OpenAI-style tool appends
/chat/completionsor/responsestobaseURL,Base URL, orOpenAI API Base, enterhttps://a.skypool.xyz/v1. - If an Anthropic / Claude-style tool appends
/v1/messages, set its Base URL tohttps://a.skypool.xyz. If it appends only/messages, usehttps://a.skypool.xyz/v1. Avoid a duplicated/v1/v1in the final URL. - If the tool requires a full
endpoint,API Endpoint, or API URL, enter the selected protocol's complete endpoint from the table and configure the tool to use that protocol's request and response formats.
The protocol name describes the wire format; model selects the actual platform model. The target model needs an available node that supports the selected protocol. You can first select the same protocol in Skypool Playground to verify it before configuring the tool.
OpenAI-compatible protocol: /v1/chat/completions
Chat Completions sends conversations through messages and authenticates with Authorization: Bearer <consumer_api_key>. Use these request parameter recommendations:
| Parameter | Recommendation |
|---|---|
model | Use a model ID from the platform Models page or the /v1/models response |
messages | Follow the OpenAI-compatible message structure, and use the tool role for tool results |
stream | Set to true for chat, agent, and long-output scenarios |
stream_options.include_usage | Set to true for streaming requests so usage and billing are easier to verify |
reasoning_effort | For Qwen3.8, use low, medium, or xhigh to enable reasoning and none to disable it |
max_tokens | Set an explicit output limit to avoid uncontrolled usage on long tasks |
temperature | For production tasks, start with a lower value and tune it for your business case |
tools | Use the OpenAI-compatible tools structure when function calling is needed |
Read non-streaming text from choices[0].message.content. For streaming, read choices[].delta, handle the final usage frame and error events, and recognize data: [DONE] as normal completion. See Control Qwen3.8 reasoning consistently for detailed reasoning parameter rules.
OpenAI Responses protocol: /v1/responses
/v1/responses accepts text or a message array in input, uses max_output_tokens for the output limit, and authenticates with Authorization: Bearer <consumer_api_key>. A minimal request is:
curl -X POST "https://a.skypool.xyz/v1/responses" \ -H "Authorization: Bearer <consumer_api_key>" \ -H "Content-Type: application/json" \ --data-raw '{ "model": "qwen3.8:27b", "input": "Give me a TypeScript HTTP request example.", "max_output_tokens": 512, "store": false, "stream": false }'Responses use the native output array, with text in the content of message output items. Streaming uses events such as response.output_text.delta and response.completed. Tools should parse the Responses format and handle response.failed, response.incomplete, and error events.
The platform currently uses stateless forwarding: include conversation history explicitly in input for subsequent turns. Continuation through previous_response_id or conversation, as well as store: true and background: true, is unsupported. Disable these features if the tool enables them automatically.
Claude protocol: /v1/messages
/v1/messages uses a messages array and requires a positive integer max_tokens. Put system instructions in the top-level system field. The platform supports x-api-key: <consumer_api_key> authentication and also accepts Authorization: Bearer <consumer_api_key>. Use the tool's native Anthropic headers and include anthropic-version, for example:
curl -X POST "https://a.skypool.xyz/v1/messages" \ -H "x-api-key: <consumer_api_key>" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ --data-raw '{ "model": "qwen3.8:27b", "system": "You are a TypeScript assistant. Answer concisely.", "messages": [ { "role": "user", "content": "Give me an HTTP request example." } ], "max_tokens": 512, "stream": false }'Responses use native content blocks and stop_reason. Streaming uses events such as content_block_delta, message_delta, and message_stop, and may return an error event. Tool calls and results use native Messages tool_use / tool_result content blocks.
Both examples support streaming by setting stream: true (add -N when using curl). Read completion events and usage according to the selected protocol. Responses and Messages do not require the Chat Completions stream_options.include_usage field, and clients must not wait only for data: [DONE] to detect completion.
Common tool integrations
- WorkBuddy integration
- OpenCode integration
- Cline integration
- Dify integration
- LiteLLM integration
- Vercel AI SDK integration
Review activity records
After a request completes, return to the Activity page in the Consumer console. You can review request time, model, status, Token usage, failure reason, and billing information there.
If you are debugging a third-party tool, first use curl or Skypool Playground to verify the same key and model, then migrate the same parameters into the tool configuration. This helps you quickly tell whether the issue is on the platform call path or in the tool-side configuration.
Common errors
| Symptom | Check first |
|---|---|
401 or authentication failure | Whether the API Key was copied completely, and whether the request uses the Authorization: Bearer header |
402 or insufficient balance | Whether the account has enough credits |
404 or model not found | Whether model comes from the current platform model list |
429 or rate limiting | Whether concurrency is too high, and whether you need to lower concurrency or split requests across keys |
5xx or node unavailable | Retry later, and check the failure semantics in activity records |
| Tool keeps waiting | Whether the streaming client correctly handles data: [DONE] and error events |
Minimum onboarding checklist
- Log in to the console and create a Consumer API Key
- Choose a model ID from the Models page or
/v1/models - Set your OpenAI-compatible client's
baseURLtohttps://a.skypool.xyz/v1 - Carry the API Key as a Bearer Token
- Verify the basic call with a non-streaming
curlrequest first - Then enable streaming output and tool calls
- Check status, usage, and failure reasons in activity records