Build a Pricing Change Runbook for OpenAI-Compatible Chinese AI SDKs
Chinese model APIs are now changing quickly enough that SDK maintainers need a release process for pricing, not just a README table. DeepSeek's official pricing page says new V4 peak and off-peak prices take effect on August 16, 2026 at 16:00 UTC. Kimi K3 publishes separate cache-hit and cache-miss input rates for long-context API use. Z.AI lists GLM cached-input and output rates across text, vision, tools, and agents. QwenCloud documents pay-as-you-go billing by modality, context tier behavior, Batch API options, context caching, thinking-token billing, and tool fees.
That is a lot of change for a normal application. It is even more sensitive for an OpenAI-compatible SDK or gateway because the caller expects a stable interface while the provider market underneath it keeps moving. The SDK may accept the same chat.completions.create() call, but the bill behind that call can change by model version, cache state, UTC window, output cap, context length, and fallback path.
This article shows a practical pricing-change runbook for Tier 1 and Tier 2 engineering teams that expose Chinese AI models through a unified API. The pattern is deliberately operational: keep append-only pricing snapshots, detect source drift in CI, make cost assumptions visible in SDK responses, and roll out new route weights only after the dated snapshot is acknowledged. The examples use neutral OpenAI-compatible shapes and placeholders only. They work with direct provider integrations or with a unified endpoint such as AIWave's model and chat APIs.
Why Pricing Needs a Runbook
Most SDKs start with a static model catalog:
| Model | Provider | Input | Output | Context |
|---|---|---|---|---|
| deepseek-v4-flash | DeepSeek | configured in code | configured in code | 1M |
| deepseek-v4-pro | DeepSeek | configured in code | configured in code | 1M |
| kimi-k3 | Moonshot Kimi | configured in code | configured in code | 1M |
| glm-5.1 | Z.AI | configured in code | configured in code | provider page |
| qwen route | QwenCloud | configured in code | configured in code | tiered |
That table is convenient, but it hides the actual production problem. The model catalog is not the pricing contract. A production contract also needs:
| Dimension | Why it matters |
|---|---|
| Effective date | A request made before a price change should be explained with the old snapshot. |
| Source URL | Finance and SRE need to know which provider page was used. |
| Cache state | Cache-hit input and cache-miss input are separate billing dimensions. |
| Time window | DeepSeek's current docs introduce peak and off-peak billing windows. |
| Context tier | QwenCloud documents long-context tier behavior and separate modality rules. |
| Tool usage | Z.AI lists separate tool and modality costs. |
| Output cap | Completion tokens often dominate cost when input is cached. |
If those dimensions live only in a spreadsheet, the SDK can ship stale behavior. If they live inside the routing layer, every request can carry the same assumptions used by the estimator, the router, and the later invoice review.
Current Source Snapshot for August 16, 2026
Use dated facts, not memory. Before changing route weights today, the pages to inspect are:
| Provider | Source checked | Operational note |
|---|---|---|
| DeepSeek | Models & Pricing | V4 Flash and V4 Pro list 1M context, cache-hit input, cache-miss input, output rates, concurrency limits, and an August 16, 2026 effective time for peak and off-peak billing. |
| DeepSeek | Rate Limit | Account-level concurrency limits affect production route capacity, not only unit price. |
| Kimi | Kimi K3 Pricing | Kimi K3 lists $3.00 per 1M cache-miss input tokens, $0.30 per 1M cache-hit input tokens, and $15.00 per 1M output tokens. |
| Z.AI | Pricing | GLM-5.2 and GLM-5.1 list $1.40 per 1M input tokens, $0.26 per 1M cached input tokens, and $4.40 per 1M output tokens. |
| QwenCloud | Pricing | The page documents pay-as-you-go billing, separate input and output text billing, long-context tiers, Batch API behavior, context caching, thinking-token billing, failed-call billing behavior, and tool fees. |
| AIWave | Models and Pricing | A unified gateway should expose model ownership, route names, and billing fields without forcing the caller to learn every upstream shape. |
The exact table should be maintained in your own repository as data, not copied into SDK code by hand. The point of the runbook is to make a source change reviewable.
Step 1: Store Append-Only Pricing Snapshots
Create one JSON file per effective date. Do not overwrite an old file when a provider updates a page. Historical requests need historical assumptions.
{
"snapshot_date": "2026-08-16",
"currency": "USD",
"sources": [
{
"provider": "deepseek",
"url": "https://api-docs.deepseek.com/quick_start/pricing/",
"checked_at": "2026-08-16T21:00:00+08:00"
},
{
"provider": "kimi",
"url": "https://www.kimi.com/resources/kimi-k3-pricing",
"checked_at": "2026-08-16T21:00:00+08:00"
}
],
"models": {
"deepseek-v4-flash": {
"provider": "deepseek",
"effective_from": "2026-08-16T16:00:00Z",
"input_cache_hit_per_1m": 0.0028,
"input_cache_miss_per_1m": 0.14,
"output_per_1m": 0.28,
"notes": "Check peak and off-peak windows before route rollout."
},
"kimi-k3": {
"provider": "kimi",
"effective_from": "2026-08-12T00:00:00Z",
"input_cache_hit_per_1m": 0.30,
"input_cache_miss_per_1m": 3.00,
"output_per_1m": 15.00,
"notes": "Long-context use benefits from stable cache keys."
}
}
}
The notes field is not decorative. It lets reviewers capture constraints that cannot be represented as a single number. For example, DeepSeek's current V4 page includes peak and off-peak behavior. QwenCloud's page includes context tiers and billing categories beyond text. Z.AI includes tool and modality costs. Those rules should be linked to route policy, not hidden in comments.
Step 2: Fail CI When Pricing Inputs Drift
The CI job does not need to scrape every number perfectly. It needs to detect that a source changed and force a human review before route weights or SDK estimates are released.
import hashlib
import json
import os
from pathlib import Path
from urllib.request import Request, urlopen
SNAPSHOT = Path("pricing/snapshots/2026-08-16.json")
def fetch_text(url: str) -> str:
request = Request(url, headers={"User-Agent": "PricingSnapshotBot/1.0"})
with urlopen(request, timeout=20) as response:
return response.read().decode("utf-8", errors="replace")
def stable_hash(text: str) -> str:
# Hash the visible pricing page enough to detect changes. Store the hash
# beside the reviewed snapshot after approval.
compact = " ".join(text.split())
return hashlib.sha256(compact.encode("utf-8")).hexdigest()
def main() -> int:
snapshot = json.loads(SNAPSHOT.read_text(encoding="utf-8"))
current = {}
for source in snapshot["sources"]:
current[source["provider"]] = stable_hash(fetch_text(source["url"]))
expected_path = SNAPSHOT.with_suffix(".hashes.json")
if not expected_path.exists():
print(json.dumps(current, indent=2))
print("Write these hashes after the pricing snapshot is reviewed.")
return 1
expected = json.loads(expected_path.read_text(encoding="utf-8"))
if current != expected:
print("Pricing source drift detected.")
print(json.dumps({"expected": expected, "current": current}, indent=2))
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
This is intentionally conservative. A changed provider page does not always mean a changed price. It may be a layout update, a new FAQ, or a marketing page adjustment. CI should not auto-publish new numbers. It should stop the release and ask for a dated review.
Step 3: Put the Snapshot ID in SDK Responses
Developers do not need a lecture on every provider price sheet. They do need to know which snapshot powered a request estimate.
{
"id": "chatcmpl_...",
"object": "chat.completion",
"model": "deepseek-v4-flash",
"usage": {
"prompt_tokens": 18320,
"completion_tokens": 740,
"total_tokens": 19060
},
"aiwave": {
"route": "coding-execution",
"pricing_snapshot": "2026-08-16",
"cache_status": "miss",
"estimated_cost_usd": 0.00277,
"source_urls": [
"https://api-docs.deepseek.com/quick_start/pricing/"
]
}
}
The extra object should be optional and namespaced so it does not break OpenAI-compatible clients. When present, it gives product, finance, and SRE teams the same debugging vocabulary: model, route, cache status, output tokens, snapshot date, and estimated cost.
Step 4: Estimate With Cache and Time Windows
Here is a minimal estimator. It is not a billing system. It is the small piece of logic that prevents a route rollout from ignoring cache state or effective date.
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timezone
@dataclass(frozen=True)
class ModelPrice:
input_cache_hit_per_1m: float
input_cache_miss_per_1m: float
output_per_1m: float
effective_from: datetime
def is_peak_utc(now: datetime) -> bool:
hour = now.astimezone(timezone.utc).hour
return 1 <= hour < 4 or 6 <= hour < 10
def estimate_cost(
price: ModelPrice,
prompt_tokens: int,
completion_tokens: int,
cache_hit: bool,
now: datetime,
peak_multiplier: float = 1.0,
off_peak_multiplier: float = 0.5,
) -> float:
if now < price.effective_from:
raise ValueError("pricing snapshot is not yet effective")
input_rate = (
price.input_cache_hit_per_1m
if cache_hit
else price.input_cache_miss_per_1m
)
output_rate = price.output_per_1m
time_multiplier = peak_multiplier if is_peak_utc(now) else off_peak_multiplier
input_cost = prompt_tokens / 1_000_000 * input_rate * time_multiplier
output_cost = completion_tokens / 1_000_000 * output_rate * time_multiplier
return round(input_cost + output_cost, 8)
Keep the time-window policy explicit. If a provider page says a new billing window is active, the estimator should require an effective timestamp. If a route has no such rule, set both multipliers to 1.0 and document why.
Step 5: Block Stale Route Rollouts
The route policy should reference a pricing snapshot. That makes stale rollouts visible during code review.
route: coding-execution
target_regions:
- US
- GB
- DE
- JP
pricing_snapshot: "2026-08-16"
primary:
model: deepseek-v4-flash
max_output_tokens: 4096
require_cache_key: true
fallbacks:
- model: glm-5.1
max_output_tokens: 4096
- model: qwen-compatible-route
max_output_tokens: 2048
rollout:
canary_percent: 5
halt_if_estimate_delta_pct_exceeds: 15
When the SDK starts, validate the policy against the pricing data:
import json
from pathlib import Path
def load_route_policy(path: str) -> dict:
# Use a YAML parser in production. JSON keeps this example dependency-light.
return json.loads(Path(path).read_text(encoding="utf-8"))
def validate_policy(policy: dict, pricing_snapshot: dict) -> None:
expected = pricing_snapshot["snapshot_date"]
actual = policy.get("pricing_snapshot")
if actual != expected:
raise RuntimeError(
f"route policy uses pricing snapshot {actual}, expected {expected}"
)
model_names = set(pricing_snapshot["models"])
route_models = [policy["primary"]["model"]]
route_models.extend(item["model"] for item in policy.get("fallbacks", []))
missing = [model for model in route_models if model not in model_names]
if missing:
raise RuntimeError(f"route policy references unpriced models: {missing}")
The important part is not the parser. The important part is that route changes and price changes become the same release surface.
Step 6: Make the Rollout Observable
A pricing change is not complete when the pull request merges. Watch it in production. For a unified endpoint, emit one event per request with the fields required for later review:
| Field | Example | Reason |
|---|---|---|
tenant_id_hash |
acct_4d9... |
Attribute cost without exposing customer identity. |
route |
coding-execution |
Compare behavior by workload. |
model |
deepseek-v4-flash |
Join to pricing snapshot. |
pricing_snapshot |
2026-08-16 |
Reconstruct dated assumptions. |
cache_status |
hit or miss
|
Explain input cost differences. |
prompt_tokens |
18320 |
Estimate input cost. |
completion_tokens |
740 |
Estimate output cost. |
estimated_cost_usd |
0.00277 |
Compare with later provider usage. |
fallback_count |
0 |
Detect hidden retry cost. |
provider_status |
200 |
Separate billing drift from request failures. |
For the first day after a price change, review four charts every few hours:
| Chart | Stop condition |
|---|---|
| Estimate per 1K requests by route | More than the approved delta. |
| Cache-hit ratio by route | Unexpected cache misses after SDK release. |
| Output tokens by model | Completion caps not being enforced. |
| Fallback rate by provider | Retry path consuming the budget. |
This is where a unified API can help. If each app team calls every provider directly, each team has to rebuild source tracking, snapshot storage, and cache-aware estimation. If the gateway exposes consistent route metadata, SDK teams can focus on product behavior while still giving finance and SRE enough evidence to review the bill.
A Practical Release Checklist
Use this checklist before changing model weights, SDK defaults, or published pricing examples:
| Check | Owner | Pass condition |
|---|---|---|
| Source review | Engineering | Official pricing URLs opened and dated. |
| Snapshot update | SDK maintainer | New append-only JSON file committed. |
| Hash update | Release manager | CI hashes match reviewed pages. |
| Route policy update | Platform team | Route references the new snapshot ID. |
| Runtime metadata | SDK maintainer | Responses expose optional pricing snapshot metadata. |
| Canary | SRE | Estimate delta stays inside the approved bound. |
| Invoice review | Finance or platform owner | Provider usage matches estimates within tolerance. |
Do not tie this runbook only to DeepSeek. DeepSeek's August 16 change is the obvious trigger today, but the same pattern applies to Kimi's cache economics, GLM tool and modality costs, and QwenCloud's context tiers. Any model market where the API remains compatible while billing rules diverge needs a dated pricing control plane.
Final Takeaway
OpenAI-compatible routing makes Chinese AI models easier to adopt, but compatibility at the request layer does not remove billing complexity. The teams that handle this well will not be the teams with the longest spreadsheet. They will be the teams that treat pricing as versioned production data.
For an SDK maintainer, that means four habits: source pricing from official pages, store append-only snapshots, bind route policies to snapshot IDs, and expose enough metadata for customers to understand what happened. With that runbook in place, DeepSeek, Kimi, GLM, Qwen, and unified gateways such as AIWave can be evaluated as production routes instead of one-off experiments.
Top comments (0)