Documentation

Flashline is a focused, OpenAI-compatible gateway for deepseek-v4.1-flash and accountless glm-5.3-flash. One request shape, independent provider queues, and a ledger that tells you exactly what each call cost.

Quickstart

Create an account, then create an API key in the dashboard. The base URL is:

__BASE_URL__

Send the key as a bearer token and include the OpenCode client headers. The canonical model IDs are deepseek-v4.1-flash and glm-5.3-flash.

curl __BASE_URL__/chat/completions \
  -H "Authorization: Bearer $FLASHLINE_KEY" \
  -H "X-Title: opencode" \
  -H "X-Flashline-Client: opencode" \
  -H "X-Flashline-Client-Token: $FLASHLINE_CLIENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [
      { "role": "user", "content": "Explain SSE in one sentence." }
    ]
  }'

You can also use x-api-key: $FLASHLINE_KEY. The gateway accepts the OpenAI chat-completions and responses request shapes. Change "model" to "glm-5.3-flash" to use the accountless guest GLM path; it supports "reasoning_effort": "low" | "high" | "max".

Authentication

Every /v1/* request needs a valid key and the OpenCode client headers. Dashboard keys start with sk-fl-, are billed against your prepaid balance, and can be revoked individually. The operator key is separate and unbilled; it is intended for internal tooling and the OpenCode provider.

This gateway is OpenCode-only. Requests from other harnesses are rejected with 403 opencode_client_required, even when the API key is valid. The client token is issued by the operator and must be kept private.
HeaderValue
AuthorizationBearer sk-fl-…
x-api-keysk-fl-… (alternative)
X-Titleopencode
X-Flashline-Clientopencode
X-Flashline-Client-TokenClient token from the operator
Content-Typeapplication/json

Configure the same headers in the OpenCode provider:

"deepseek-web": {
  "headers": {
    "X-Title": "opencode",
    "X-Flashline-Client": "opencode",
    "X-Flashline-Client-Token": "<client token>",
    "User-Agent": "opencode/2.0.18"
  }
}

Models

deepseek-v4.1-flash uses the exported DeepSeek Web account. glm-5.3-flash uses the z.ai guest Web protocol, is browserless and accountless, and starts in thinking mode with reasoning_effort: "max". Guest GLM supports only the Flash model; glm-5.3 and glm-5.2 require a logged-in z.ai browser session and are not served. Pro, expert, and unknown IDs are rejected with 400 model_not_found instead of being silently remapped.

curl __BASE_URL__/models \
  -H "Authorization: Bearer $FLASHLINE_KEY" \
  -H "X-Title: opencode" \
  -H "X-Flashline-Client: opencode" \
  -H "X-Flashline-Client-Token: $FLASHLINE_CLIENT_TOKEN"
{
  "object": "list",
  "data": [
    { "id": "deepseek-v4.1-flash", "object": "model", "owned_by": "deepseek-web" },
    {
      "id": "glm-5.3-flash",
      "object": "model",
      "owned_by": "z.ai-web",
      "metadata": {
        "provider": "zchat.z.ai",
        "thinking_effort_levels": ["low", "high", "max"],
        "default_thinking_effort": "max"
      }
    }
  ]
}

Chat completions

POST /v1/chat/completions accepts an OpenAI-style messages array. Use the model ID exactly as listed.

FieldTypeNotes
modelstringRequired in practice; use deepseek-v4.1-flash or glm-5.3-flash.
messagesarraysystem, user, and assistant roles. Text content is supported.
streambooleanSet true for SSE chunks.
thinkingbooleanThinking is on by default. Set false to disable it.
web_searchbooleanRequests upstream web search. A per-request search fee applies.
reasoning_effortstringGLM only: low, high, or max (default).
previous_response_idstringContinue a conversation returned by a previous call.
conversationstringExplicit conversation/session ID. Must belong to the same account.

Non-streaming responses include an OpenAI-compatible message plus a usage object. For billed keys, usage.cost_usd and usage.balance_usd are included, along with a billing receipt.

{
  "id": "chatcmpl_…",
  "object": "chat.completion",
  "model": "deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "…" },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 28,
    "completion_tokens": 64,
    "total_tokens": 92,
    "cost_usd": 0.0000426,
    "balance_usd": 0.2499574
  },
  "billing": {
    "costUsd": 0.0000426,
    "peak": false,
    "phase": "off-peak",
    "legacy": false
  },
  "conversation": "…",
  "previous_response_id": "resp_…"
}

Responses

POST /v1/responses accepts a string input or an array of message-like items, plus optional instructions. It returns a Responses-style object with output, output_text, usage, and the same billing receipt when the key is metered.

curl __BASE_URL__/responses \
  -H "Authorization: Bearer $FLASHLINE_KEY" \
  -H "X-Title: opencode" \
  -H "X-Flashline-Client: opencode" \
  -H "X-Flashline-Client-Token: $FLASHLINE_CLIENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "instructions": "Answer in one short paragraph.",
    "input": "What is a token, really?"
  }'

Set stream: true to receive Responses-style SSE events, ending with a response.usage event and data: [DONE].

Streaming

Chat streaming emits chat.completion.chunk events. Reasoning text arrives as delta.reasoning_content; answer text arrives as delta.content. The final chunk carries finish_reason: "stop" and a usage object, followed by data: [DONE].

curl -N __BASE_URL__/chat/completions \
  -H "Authorization: Bearer $FLASHLINE_KEY" \
  -H "X-Title: opencode" \
  -H "X-Flashline-Client: opencode" \
  -H "X-Flashline-Client-Token: $FLASHLINE_CLIENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4.1-flash",
    "messages": [{ "role": "user", "content": "Write a haiku about latency." }],
    "stream": true
  }'
Proxy note: disable response buffering and compression for SSE. Send Cache-Control: no-cache and keep the connection open until [DONE]. The gateway flushes each upstream fragment as it arrives.

Tool calling

Both models accept OpenAI-style tools. DeepSeek Web and guest GLM do not expose a native client-tool API, so Flashline bridges calls through a compact prompt and parses the model's call markup. Use the same tools schema you would send to OpenAI.

  • Chat completions: the assistant message has content: null, a tool_calls array, and finish_reason: "tool_calls". Streaming sends the calls as delta.tool_calls chunks.
  • Responses: the output contains a function_call item with call_id, name, and arguments. Streaming emits response.function_call_arguments.* and response.output_item.* events.
  • Continuations: send the tool result back with the returned previous_response_id or conversation. The gateway reuses the upstream chat, so the full transcript is not replayed.
  • GLM: client tools disable the guest model's built-in web search/fetch for that request. GLM calls are parsed from <tool_call>{...}</tool_call> or bare JSON; DeepSeek's DSML markup is not used on GLM.
  • Best effort: malformed or unknown tool names are ignored, and invalid arguments are passed through so your tool can return an error. Tool results count as billed input tokens.
{
  "model": "glm-5.3-flash",
  "messages": [{ "role": "user", "content": "What is the weather in Paris?" }],
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get current weather",
      "parameters": {
        "type": "object",
        "properties": { "city": { "type": "string" } },
        "required": ["city"]
      }
    }
  }]
}
Example assistant response
{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [{
        "id": "call_abc123",
        "type": "function",
        "function": { "name": "get_weather", "arguments": "{\"city\":\"Paris\"}" }
      }]
    },
    "finish_reason": "tool_calls"
  }]
}

Conversations

DeepSeek and guest GLM keep conversation state upstream. Flashline scopes every session to the account that created it, so two users with the same prompt never share a conversation. You can continue a turn in three ways:

  • Pass the returned previous_response_id (resp_…) with your next message.
  • Pass the returned conversation ID explicitly.
  • Send the full messages history; the gateway matches it to the existing session.

If an ID belongs to another account, the request returns 404 conversation_not_found.

Billing

User keys are prepaid and metered. Each request reserves a projected amount, then settles against the final token counts. The current phase (peak or off-peak) is determined at request start using the published UTC windows. Input is billed at the cache-miss rate.

Token accounting: the DeepSeek Web upstream does not expose exact completion-token counts. Flashline estimates input from the request body and output from the generated text, including reasoning (CJK ≈1 token/char, other text ≈4 chars/token). The upstream accumulated_token_usage field is the chat's context-window fill, not output; Responses API calls expose it as metadata.upstream_context_tokens and it is never billed as completion tokens.
ItemOff-peakPeak
Input · cache miss$0.15 / 1M$0.30 / 1M
Output$0.60 / 1M$1.20 / 1M
Input · cache hit (reference)$0.003 / 1M$0.006 / 1M
Web search$0.00075 / request$0.00075 / request

Peak hours are 01:00–04:00 and 06:00–10:00 UTC, Monday–Friday, excluding Chinese public holidays. Rates can be adjusted by the operator; the live values are always shown on the pricing section and in the dashboard.

GLM-5.3-Flash guest billing

GLM has a separate price book with flat Z.ai list rates and no peak/off-peak phase. Usage rows and receipts include provider: "glm" and the actual model. Cached input tokens are billed at the cached rate when the upstream reports them.

ItemPrice
Input · cache miss$0.15 / 1M
Input · cached$0.03 / 1M
Output$0.50 / 1M
Web search$0.01 / request

An empty balance returns 402 insufficient_balance before the upstream call is made. A request already in flight may settle slightly below zero; the next request is blocked until credit is added.

Limits

LimitUser keyOperator key
Requests per minute60240
Concurrent requests per account3—
QueueingIndependent DeepSeek and GLM lanes; excess requests waitSame
Request body24 MB24 MB

Limits are enforced at the gateway and can be tuned by the operator. Exceeding a limit returns 429 with a code such as rate_limited, too_many_requests, or server_busy.

Errors

StatusCodeMeaning
400model_not_foundThe requested model is not served by this gateway.
400invalid_jsonThe body is not a JSON object.
401invalid_api_keyMissing or unknown key.
402insufficient_balanceNo prepaid credit available.
403account_disabledThe account has been disabled.
403opencode_client_requiredMissing or incorrect OpenCode client headers.
404conversation_not_foundThe conversation ID is unknown or belongs to another account.
413payload_too_largeThe body exceeds the gateway limit.
429rate_limitedPer-minute request limit reached.
429too_many_requestsPer-account concurrency limit reached.
429server_busyThe provider queue is full. Try again shortly.
500 / 502glm_upstreamThe guest GLM upstream failed or returned an empty response.
502glm_blockedThe guest GLM completion was blocked by the upstream WAF (HTTP 405). Retry later.
503provider_disabledGLM is disabled on this deployment.

Errors use the shape { "error": { "message": "…", "code": "…" } }. Streaming errors are sent as an SSE event before the stream closes.

DeepSeek Web sometimes returns an empty turn or ends a tool turn with a plan instead of a tool call. The gateway retries empty turns with a recovery prompt and continues announced-but-unexecuted tool steps automatically. Retried attempts are not streamed, so the client only sees the successful attempt. If every retry is empty, the response contains a [Gateway] fallback message that asks the client to retry.

Health & models

GET /health is public and returns uptime, user count, request count, and the served models. GET /v1/models requires a key plus the OpenCode client headers and lists deepseek-v4.1-flash plus glm-5.3-flash when GLM is enabled.

curl __ORIGIN__/health

curl __BASE_URL__/models \
  -H "Authorization: Bearer $FLASHLINE_KEY" \
  -H "X-Title: opencode" \
  -H "X-Flashline-Client: opencode" \
  -H "X-Flashline-Client-Token: $FLASHLINE_CLIENT_TOKEN"
Dashboard: keys, usage rows, top-up requests, promos, referrals, and balance adjustments all live in the Flashline dashboard. The operator can review manual top-ups and change the price book from the Admin area.

Support

For account issues, use the Billing page to submit a top-up request with a note, or contact the operator of this Flashline deployment. Flashline is an independent gateway and is not affiliated with DeepSeek.