Short version: Kimi K3's $3/M list input price is the price you pay for tokens the cache misses. Cache-hit input is $0.30/M — ten times cheaper — and with the ~92% cache-hit rate providers report, the effective input price is about $0.52/M. The catch: the cache is prefix-based, so you only get it if the stable part of your prompt comes first and the variable part comes last. Get the ordering right and the discount is automatic. Get it wrong and you pay list price on every call. Here's the setup.
1. Connect — it's just the OpenAI SDK#
Every major provider serves Kimi K3 through an OpenAI-compatible endpoint, so you don't need a new client. Only three things change per provider: base_url, api_key, and the model id.
from openai import OpenAI
# OpenRouter (routes across upstream providers)
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="sk-or-...",
)
MODEL = "moonshotai/kimi-k3"
# Moonshot direct, Together, Fireworks, SiliconFlow all follow the same shape:
# a different base_url + api_key + their own K3 model string.
Confirm the exact model string on each provider's model page before you ship — the protocol is identical, only the id differs.
2. The one rule that sets your bill: stable content first#
Kimi K3's cache matches the longest identical leading prefix of your request. Tokens inside that match bill at $0.30/M; everything after the first difference bills at the full $3.00/M. So the entire game is prompt ordering:
- First (stable, cached): system prompt → tool/function definitions → retrieved documents → few-shot examples
- Last (variable, uncached): the user's newest message
messages = [
# --- stable prefix: identical on every call, so it caches ---
{"role": "system", "content": SYSTEM_PROMPT}, # fixed
{"role": "system", "content": RETRIEVED_CONTEXT}, # fixed per session
*FEW_SHOT_EXAMPLES, # fixed
# --- variable suffix: only this changes, so only this pays full price ---
{"role": "user", "content": user_turn}, # changes every call
]
resp = client.chat.completions.create(
model=MODEL,
messages=messages,
max_tokens=1024, # cap output — output is NEVER cached and bills at $15/M
)
Move one variable token ahead of the stable block — a timestamp in the system prompt, a per-request id spliced early — and you invalidate the cache for the whole request. This is the single most common reason a team's "cheap" model quietly bills at list price.
3. Verify the cache is actually hitting#
Don't trust that it's working — measure it. Read the usage object on every response and compute your real hit rate:
u = resp.usage
# field names vary by provider; look for cached / cache-read counters
cached = getattr(u, "prompt_cache_hit_tokens", 0) or 0
total_in = u.prompt_tokens
hit_rate = cached / total_in if total_in else 0.0
print(f"cache hit: {hit_rate:.0%} in={total_in} cached={cached} out={u.completion_tokens}")
If hit_rate sits well below ~90%, your ordering is wrong — something variable is sitting ahead of something stable. Fix it and the rate (and the bill) improve on the next call. This is the same instrument-then-tune discipline we apply to context editing's cache cost.
4. Do the math so you know what you're paying#
At list price, 1M input tokens cost $3.00. At the cache-hit rate they cost $0.30. Blend them at a 92% hit rate:
effective input = 0.92 × $0.30 + 0.08 × $3.00
≈ $0.28 + $0.24
≈ $0.52 per million input tokens
That's the number to plan against — roughly a 6× discount off list, earned entirely by prompt ordering. Output is the part caching can't touch: it bills at $15/M every time, so it's usually your biggest line item. Cap max_tokens, keep responses tight, and route genuinely high-output-volume work on purpose rather than by accident.
5. Where this leaves you#
Kimi K3 via API, cached well, is one of the cheapest frontier-class models a solo founder can run — and far cheaper than self-hosting the open weights, which needs a 32×H100-class cluster you'd never keep busy. Structure the prompt with stable content first, measure your hit rate off the usage fields, cap your output, and keep the app model-swappable so you can cost-route per task. The $0.52 effective price isn't a promotion — it's just what you pay once the cache is doing its job.



