How to Read DeepSeek Token Usage and Cache Fields

DeepSeek token usage is reported in the usage object of a Chat Completions response. The key is to separate input tokens that hit the context cache from input tokens that miss it, then treat generated tokens as a third billing bucket. This guide shows how to read every field, verify the totals, calculate cache-hit rate and estimated cost, and capture usage in Node.js, Python, and streamed responses.

Last verified by Chat-Deep.ai: July 21, 2026.

Independent guide: Chat-Deep.ai is not affiliated with, endorsed by, or operated by DeepSeek. Field definitions, model IDs, cache behavior, and prices were checked against DeepSeek’s first-party documentation. Verify production billing against the official documentation and your account records.

Quick answer

For a non-streaming response, read response.usage. DeepSeek’s documented relationships are:

prompt_tokens = prompt_cache_hit_tokens + prompt_cache_miss_tokens
total_tokens  = prompt_tokens + completion_tokens
cache_hit_rate = prompt_cache_hit_tokens / prompt_tokens

For cost, do not multiply total_tokens by one price. Apply the cache-hit input rate to prompt_cache_hit_tokens, the cache-miss input rate to prompt_cache_miss_tokens, and the output rate to completion_tokens. If completion_tokens_details.reasoning_tokens is returned, it is a breakdown within the completion count—not a fourth amount to add again.

On this page

DeepSeek token usage field reference

The first-party DeepSeek Chat Completions schema documents the following fields under usage.

The five main counters are documented as required in the non-streaming usage schema; completion_tokens_details and its nested reasoning count are optional. The API does not return a dollar cost or a cache_hit_rate field—both are derived in your application.

FieldWhat it measuresHow to use it
prompt_tokensAll input tokens processed for the request, including cache hits and cache misses.Use as total input and as the cache-hit-rate denominator.
prompt_cache_hit_tokensInput tokens that matched a persisted context-cache prefix.Apply the model’s cache-hit input rate.
prompt_cache_miss_tokensInput tokens that did not hit the context cache.Apply the model’s cache-miss input rate.
completion_tokensTokens generated for the completion.Apply the output-token rate.
total_tokensPrompt tokens plus completion tokens.Use for capacity and volume monitoring, not as a single-price billing bucket.
completion_tokens_details.reasoning_tokensReasoning tokens generated by the model when applicable.Track thinking usage, but do not add it again to completion_tokens.

The two reconciliation checks

  • Input check: prompt_tokens must equal prompt_cache_hit_tokens + prompt_cache_miss_tokens in the documented first-party response.
  • Overall check: total_tokens must equal prompt_tokens + completion_tokens.

These checks are useful in production because they expose incomplete stream handling, field loss in a gateway, or an SDK serializer that does not preserve provider-specific properties.

Annotated DeepSeek usage response

The numbers below are illustrative; the field structure follows the documented Chat Completions schema.

{
  "usage": {
    "prompt_tokens": 12000,
    "prompt_cache_hit_tokens": 9000,
    "prompt_cache_miss_tokens": 3000,
    "completion_tokens": 950,
    "total_tokens": 12950,
    "completion_tokens_details": {
      "reasoning_tokens": 600
    }
  }
}
  • The request used 12,000 input tokens: 9,000 cache hits plus 3,000 cache misses.
  • The cache-hit rate was 75%: 9,000 / 12,000 × 100.
  • The model generated 950 completion tokens.
  • The 600 reasoning tokens are part of the completion-token breakdown. The overall token total remains 12,950, not 13,550.

Why total_tokens cannot calculate the bill by itself

Two requests can have the same total_tokens and different costs. One may have mostly cache-hit input, while the other has cache-miss input or a larger share of output. The selected model also changes all three rates. Preserve the separate counters instead of logging only the total.

Read and validate DeepSeek token usage in Node.js

This example uses the OpenAI JavaScript package with DeepSeek’s OpenAI-compatible base URL. Keep the API key in a server-side environment variable; an account password is not an API credential. For the complete connection setup, use the DeepSeek API guide.

import OpenAI from "openai";

if (!process.env.DEEPSEEK_API_KEY) {
  throw new Error("Set DEEPSEEK_API_KEY on the server.");
}

const model = "deepseek-v4-flash";
const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

const response = await client.chat.completions.create({
  model,
  messages: [
    {
      role: "system",
      content: "You are a concise technical analyst.",
    },
    {
      role: "user",
      content: "Explain context caching in three bullet points.",
    },
  ],
  thinking: { type: "enabled" },
  stream: false,
});

const usage = response.usage;
if (!usage) {
  throw new Error("The response did not include a usage object.");
}

const requiredFields = [
  "prompt_tokens",
  "prompt_cache_hit_tokens",
  "prompt_cache_miss_tokens",
  "completion_tokens",
  "total_tokens",
];

for (const field of requiredFields) {
  if (typeof usage[field] !== "number") {
    throw new Error(`Missing or invalid usage.${field}`);
  }
}

const promptTokens = usage.prompt_tokens;
const hitTokens = usage.prompt_cache_hit_tokens;
const missTokens = usage.prompt_cache_miss_tokens;
const completionTokens = usage.completion_tokens;
const totalTokens = usage.total_tokens;
const reasoningTokens =
  usage.completion_tokens_details?.reasoning_tokens ?? 0;

if (promptTokens !== hitTokens + missTokens) {
  throw new Error("Prompt token counters do not reconcile.");
}

if (totalTokens !== promptTokens + completionTokens) {
  throw new Error("Total token counters do not reconcile.");
}

const cacheHitRate = promptTokens > 0
  ? (hitTokens / promptTokens) * 100
  : 0;

const pricesPerMillion = {
  "deepseek-v4-flash": { hit: 0.0028, miss: 0.14, output: 0.28 },
  "deepseek-v4-pro": { hit: 0.003625, miss: 0.435, output: 0.87 },
};

const rates = pricesPerMillion[model];
const estimatedCostUsd = (
  hitTokens * rates.hit +
  missTokens * rates.miss +
  completionTokens * rates.output
) / 1_000_000;

console.table({
  prompt_tokens: promptTokens,
  prompt_cache_hit_tokens: hitTokens,
  prompt_cache_miss_tokens: missTokens,
  completion_tokens: completionTokens,
  reasoning_tokens: reasoningTokens,
  total_tokens: totalTokens,
  cache_hit_rate_percent: Number(cacheHitRate.toFixed(2)),
  estimated_cost_usd: Number(estimatedCostUsd.toFixed(9)),
});

Important: the price constants above were verified on July 21, 2026. Keep rates in configuration rather than scattering them through application code, and update them only after checking DeepSeek’s official pricing page. Your account’s billing record remains authoritative.

TypeScript note: an OpenAI-compatible SDK’s type definitions may lag DeepSeek-specific response properties even when the raw JSON contains them. Define a narrow local interface for the documented usage shape or inspect the parsed raw response; do not silently convert missing fields to zero for billing.

Capture token usage in a streaming response

When stream: true, set stream_options.include_usage to true. DeepSeek documents an additional chunk before data: [DONE]; its usage object covers the whole request and its choices array is empty. Other chunks include usage: null, so never assume every streamed chunk contains final counters.

const stream = await client.chat.completions.create({
  model: "deepseek-v4-flash",
  messages: [
    { role: "user", content: "Give me a short deployment checklist." },
  ],
  thinking: { type: "disabled" },
  stream: true,
  stream_options: { include_usage: true },
});

let finalUsage = null;

for await (const chunk of stream) {
  const text = chunk.choices[0]?.delta?.content;
  if (text) process.stdout.write(text);

  if (chunk.usage) {
    finalUsage = chunk.usage;
  }
}

if (!finalUsage) {
  throw new Error("The stream ended without a final usage chunk.");
}

console.log("\nFinal usage:", finalUsage);

Validate and price finalUsage with the same logic used for a non-streaming response. If the client disconnects before the usage chunk arrives, do not invent a local total and label it as official usage.

For request, response, and SSE handling beyond usage metrics, see the DeepSeek Chat Completion API guide.

Read DeepSeek token usage in Python

The Python client can expose provider-specific fields as attributes or nested objects depending on the package version. This helper reads either an object attribute or a dictionary key and fails clearly when a required counter is missing.

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

response = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[
        {
            "role": "user",
            "content": "Explain cache-hit input in two sentences.",
        }
    ],
    stream=False,
    extra_body={"thinking": {"type": "disabled"}},
)

def read_field(obj, name, default=None):
    if obj is None:
        return default
    if isinstance(obj, dict):
        return obj.get(name, default)
    return getattr(obj, name, default)

usage = response.usage
required = {
    "prompt_tokens": read_field(usage, "prompt_tokens"),
    "prompt_cache_hit_tokens": read_field(
        usage, "prompt_cache_hit_tokens"
    ),
    "prompt_cache_miss_tokens": read_field(
        usage, "prompt_cache_miss_tokens"
    ),
    "completion_tokens": read_field(usage, "completion_tokens"),
    "total_tokens": read_field(usage, "total_tokens"),
}

missing = [name for name, value in required.items() if value is None]
if missing:
    raise RuntimeError(f"Missing usage fields: {', '.join(missing)}")

if required["prompt_tokens"] != (
    required["prompt_cache_hit_tokens"]
    + required["prompt_cache_miss_tokens"]
):
    raise RuntimeError("Prompt token counters do not reconcile")

if required["total_tokens"] != (
    required["prompt_tokens"] + required["completion_tokens"]
):
    raise RuntimeError("Total token counters do not reconcile")

details = read_field(usage, "completion_tokens_details")
reasoning_tokens = read_field(details, "reasoning_tokens", 0) or 0

prompt_tokens = required["prompt_tokens"]
hit_rate = (
    required["prompt_cache_hit_tokens"] / prompt_tokens * 100
    if prompt_tokens
    else 0
)

print({
    **required,
    "reasoning_tokens": reasoning_tokens,
    "cache_hit_rate_percent": round(hit_rate, 2),
})

Calculate DeepSeek API cost from usage fields

The official DeepSeek Models & Pricing page listed the following USD rates per one million tokens when this guide was verified.

API modelCache-hit inputCache-miss inputOutput
deepseek-v4-flash$0.0028$0.14$0.28
deepseek-v4-pro$0.003625$0.435$0.87
estimated_cost_usd =
  (prompt_cache_hit_tokens / 1,000,000 × cache_hit_price)
  + (prompt_cache_miss_tokens / 1,000,000 × cache_miss_price)
  + (completion_tokens / 1,000,000 × output_price)

Worked example

Using the illustrative response above—9,000 cache-hit tokens, 3,000 cache-miss tokens, and 950 completion tokens—the estimated first-party API cost is:

  • deepseek-v4-flash: $0.00071120
  • deepseek-v4-pro: $0.002164125

These are calculations from published token rates, not an invoice. Promotions, price changes, a third-party provider’s markup, or different billing rules can change what you pay. Use the DeepSeek API cost calculator for workload projections and the DeepSeek pricing guide for the broader pricing context.

What the cache fields do—and do not—mean

DeepSeek says context caching is enabled by default. A later request may hit a persisted cache unit when it fully reuses a matching prompt prefix. The output is still generated through inference; a cache hit does not replay an old answer or make completion_tokens cheaper.

  • A high hit count means input reuse: it does not mean the response was copied.
  • A zero hit count is not automatically an error: the cache is best-effort, takes time to build, and depends on persisted prefix units.
  • Exact early structure matters: changing dates, IDs, message order, whitespace, or other content near the beginning can reduce the reusable prefix.
  • Cache entries are not permanent: DeepSeek says unused entries are generally cleared within hours to days.
  • Isolation can matter: DeepSeek documents user_id as usable for KV-cache isolation, so evaluate hit rates within the same intentional isolation design.

For prefix persistence, multi-turn examples, prompt layout, cache lifetime, and privacy considerations, use the dedicated DeepSeek context caching guide.

How reasoning tokens affect usage

When thinking mode is used, the response may include completion_tokens_details.reasoning_tokens. DeepSeek defines this as tokens generated for reasoning and places it inside the completion-token breakdown. Use completion_tokens for output billing, then use reasoning_tokens as an observability metric for the share of output spent on reasoning.

reasoning_share = reasoning_tokens / completion_tokens

Guard against a zero denominator and treat a missing details object as “not reported,” not proof that every model path used zero internal computation. For thinking controls and reasoning_content, see the DeepSeek Thinking Mode guide.

What to log in production

Log one record after each completed request. Avoid storing full prompts or model output unless your security, privacy, and retention rules explicitly require them.

  • Response ID and your own correlation ID
  • Model ID and thinking-mode setting
  • prompt_tokens, cache-hit tokens, and cache-miss tokens
  • completion_tokens, reasoning tokens when reported, and total_tokens
  • Cache-hit rate and cache-miss rate
  • Estimated cost using a versioned rate table
  • Prompt-template version—not the secret or full prompt
  • Latency, HTTP status, retry count, and finish_reason

Aggregate by model, endpoint, template version, tenant or privacy-safe workload class, and time period. A site-wide average can hide one template whose changing prefix produces almost all cache misses. For dashboards, traces, and alerts beyond this field-level guide, continue to DeepSeek API observability.

Troubleshoot DeepSeek usage and cache fields

SymptomLikely explanationWhat to check
No usage object in a streaminclude_usage was not enabled, or the final usage chunk was not consumed.Set stream_options.include_usage: true, iterate until the stream ends, and handle the empty choices array.
Cache fields are absentAn older SDK type, proxy, logging layer, or third-party gateway may not preserve DeepSeek-specific fields.Inspect the parsed response from the official base URL in staging. Update the client or gateway contract; do not silently record missing fields as zero.
Every input token is a cache missThe request has no reusable persisted prefix, the early prompt changes, the cache is not ready, or isolation differs.Keep reusable instructions and context identical at the front, move volatile values later, and test several requests while preserving the intended user_id policy.
hit + miss does not equal prompt_tokensThe response is not using the documented first-party schema, a field was transformed, or the wrong stream chunk was logged.Log the raw parsed usage object, endpoint, provider, model, and SDK version; price nothing until the mismatch is explained.
Estimated cost is too high or too lowThe calculation used one rate for total_tokens, added reasoning twice, or used stale/model-mismatched rates.Price hit input, miss input, and completion separately. Version rates by model and verification date.
reasoning_tokens is missingThinking was disabled, no details object was returned, or a client dropped the provider-specific breakdown.Treat the field as optional for telemetry, confirm the thinking setting, and inspect the unmodified response shape.

Can you estimate tokens before sending a request?

DeepSeek provides an offline tokenizer demo for planning input size. Token estimates are useful for context limits, routing, and budgets, but the processed request’s returned usage values are the correct counters for request-level monitoring. Tokenization varies by model and content, so character or word counts are only rough estimates. See DeepSeek’s official Token & Token Usage guide.

Frequently asked questions

Does prompt_tokens include cached tokens?

Yes. DeepSeek documents prompt_tokens as the total prompt count and states that it equals cache-hit tokens plus cache-miss tokens.

Are DeepSeek cache-hit tokens free?

No. The first-party pricing table lists a lower input rate for cache hits and a higher input rate for cache misses. Apply the rate for the selected model and verification date.

Does total_tokens include reasoning tokens?

Reasoning tokens are reported inside completion_tokens_details, which is a breakdown of completion usage. They are therefore represented within completion_tokens and, through that count, within total_tokens. Do not add them a second time.

Why did an identical or similar request still show cache misses?

DeepSeek describes context caching as best-effort. A hit requires a full match with a persisted prefix unit, cache construction takes time, early changes can break the reusable prefix, and unused cache entries expire. Measure several representative requests instead of treating one retry as a guarantee.

Does a cache hit make output tokens cheaper?

No. Context caching applies to matching input prefixes. Output is generated again and is billed at the output rate.

How do I get DeepSeek usage data when streaming?

Send stream_options: {"include_usage": true} with stream: true. Save the non-null usage object from the additional chunk before the stream’s final marker. Its choices array is empty.

Will every OpenAI-compatible provider return these cache fields?

Not necessarily. OpenAI-format compatibility does not guarantee identical provider-specific usage fields or billing. If you use a gateway, cloud marketplace, or another model host, follow that provider’s response schema and pricing rather than assuming first-party DeepSeek fields.

Which usage value should I store?

Store all of them: prompt, hit, miss, completion, total, and reasoning tokens when reported. Derived metrics can be recalculated; discarded source counters cannot.

Primary sources

Start with the separate counters, verify both token equations, and calculate cost from the three priced buckets. That turns the DeepSeek usage object into reliable monitoring data instead of a single ambiguous total.