DeepSeek API Billing: Balance, Top-Ups, Peak Hours, and Cost Tracking

DeepSeek API billing uses prepaid account balance and token-based charges. Input is billed separately for cache hits and cache misses, while generated tokens use the output rate. Charges depend on the selected model and the applicable peak or off-peak period. Granted balance is used before topped-up balance when both are available.

To track spending reliably, check the balance, reserve an internal application budget, capture the returned token usage, calculate the local cost, and reconcile your records with the provider. Missing usage means an unknown cost—not a free request.

Last verified: October 16, 2026. This guide covers the direct DeepSeek API platform. Third-party gateways and cloud-hosted deployments can have different billing rules.

DeepSeek API billing at a glance

Billing questionCurrent answer
What is billed?Input and output tokens, with input split into cache hits and cache misses.
Which balances can pay?Granted balance and topped-up balance.
Which balance is used first?Granted balance is preferred when both are available.
How do rates vary?By model, token category, and peak or off-peak period.
How do I check funds?Use the API platform or GET /user/balance.
What stops requests when funds run out?The API returns HTTP 402 Insufficient Balance.

DeepSeek’s official pricing table defines rates and deduction rules; the Get User Balance reference defines balance fields. The budget-reservation and logging patterns below are application-design recommendations, not additional features of the balance endpoint. Keep a dated rate snapshot for each request.

How the billing workflow fits together

  1. Fund the API account. Use topped-up funds or any granted balance actually shown in the account.
  2. Check the provider balance. Review the platform or call GET /user/balance.
  3. Estimate a conservative budget. Include the complete input and the request’s output cap. Use peak rates when the applicable period is uncertain.
  4. Reserve your application budget. Do this atomically before concurrent workers begin billable work.
  5. Send the request and capture usage. Keep the requested model, returned model, request identifiers, timestamps, and token counts.
  6. Calculate or mark pending. Calculate the local cost only when usage and pricing are validated. Missing or inconsistent data must remain pending rather than becoming zero.
  7. Reconcile and settle. Release unused reservations under your settlement policy and compare local records with provider balance snapshots and confirmed account adjustments.

The balance endpoint reports the current balance; it is not a per-request billing-history endpoint. A production application still needs its own durable request ledger if it must answer questions such as “Which workspace spent this amount?” or “Which feature caused yesterday’s increase?”

Topped-up balance vs. granted balance

FieldMeaningImplementation note
is_availableWhether the user’s balance is sufficient for API calls.Use it as a provider-level availability signal, not as an application budget.
balance_infosAn array of balance entries.Do not assume the response contains exactly one object.
currencyThe entry’s currency; the schema currently allows CNY or USD.Keep currencies separate. Do not add CNY and USD balances together.
total_balanceTotal available balance, including granted and topped-up balance.The API returns the amount as a string; parse money with a decimal type.
granted_balanceTotal granted balance that has not expired.A grant is not guaranteed for every account, and the public schema does not define one universal grant amount or lifetime.
topped_up_balanceTopped-up funds reported in the current balance.This is a current balance field, not a lifetime top-up history.

For each currency, total_balance includes granted and topped-up funds. DeepSeek prefers granted funds first. Only non-expired grants are included in granted_balance; the public schema does not promise every account a credit or define a universal expiration period. A decrease in granted balance can also reflect ordinary spending, so do not classify every decrease as an expiration.

Use Python’s Decimal, a database decimal column, or an equivalent decimal type for money. Construct decimal values from the API’s strings, not from binary floating-point conversions. Keep sufficient precision in request records and round only under a defined reporting policy.

How to check your DeepSeek API balance

Check the balance with GET /user/balance

Store the API key in a trusted server-side environment variable. The Bash example below assumes DEEPSEEK_API_KEY is already set securely. Never put the key in public browser code, a repository, a screenshot, or a query string. For account setup, see how to get a DeepSeek API key.

curl --request GET "https://api.deepseek.com/user/balance" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${DEEPSEEK_API_KEY:?Set DEEPSEEK_API_KEY first}"

Read is_available first, then iterate through balance_infos and select the currency entry relevant to the account. Since the monetary fields are strings, keep them as exact decimals. Do not treat total_balance as historical spend, and do not use the balance check as if it were an atomic reservation: other workers may spend from the same provider account immediately after your check.

Review the balance and add funds in the official platform

  1. Sign in to the official DeepSeek API platform.
  2. Review the current balance shown for the API account.
  3. When funds are needed, open the official Top Up page.
  4. Use only the payment and currency options actually displayed for the signed-in account.
  5. After completion, check the platform again or call GET /user/balance to confirm that the expected topped-up balance is visible.

Use only the payment methods, currencies, amounts, and terms displayed in the signed-in account. This guide does not assume a particular card type, minimum top-up, processing time, refund entitlement, or automatic-recharge feature. The official error-code documentation links to the Top Up page; authenticated payment screens were not used for this review. Never give an unofficial top-up service your login or API key.

Current peak and off-peak pricing

The direct API lists deepseek-flash, served by DeepSeek-V4.1-Flash, and deepseek-v4-pro, served by DeepSeek-V4-Pro-0813. Pro has its own rates; do not price a Pro request using Flash rates. The official change log confirms continued Pro service after September 14, 2026. All prices below are U.S. dollars per one million tokens.

ModelToken categoryOff-peakPeak
deepseek-flashInput, cache hit$0.003$0.006
deepseek-flashInput, cache miss$0.15$0.30
deepseek-flashOutput$0.60$1.20
deepseek-v4-proInput, cache hit$0.022$0.044
deepseek-v4-proInput, cache miss$0.66$1.32
deepseek-v4-proOutput$1.98$3.96

Under the official pricing table, peak periods are 01:00–04:00 UTC and 06:00–10:00 UTC, Monday through Friday, excluding Chinese public holidays. All other hours are off-peak, including weekends and Chinese public holidays in full. Off-peak rates are half of peak rates. Apply the provider’s UTC schedule, not the local weekday alone.

U.S. time-zone conversions

Use the offset that applies to the request’s date and location. The tables below convert the published UTC windows using the U.S. Naval Observatory’s time-zone offsets. Unmarked times fall on the UTC date; “previous day” means the preceding local calendar date.

When daylight time applies:

UTC peak windowEastern (EDT)Central (CDT)Mountain (MDT)Pacific (PDT)
01:00–04:009:00 p.m. (previous day)–12:00 a.m.8:00–11:00 p.m., previous day7:00–10:00 p.m., previous day6:00–9:00 p.m., previous day
06:00–10:002:00–6:00 a.m.1:00–5:00 a.m.12:00–4:00 a.m.11:00 p.m. (previous day)–3:00 a.m.

When standard time applies:

UTC peak windowEastern (EST)Central (CST)Mountain (MST)Pacific (PST)
01:00–04:008:00–11:00 p.m., previous day7:00–10:00 p.m., previous day6:00–9:00 p.m., previous day5:00–8:00 p.m., previous day
06:00–10:001:00–5:00 a.m.12:00–4:00 a.m.11:00 p.m. (previous day)–3:00 a.m.10:00 p.m. (previous day)–2:00 a.m.

Keep scheduling logic in UTC and convert only for display. Not every U.S. location observes daylight saving time; use a date-aware time-zone conversion rather than assuming one offset year-round. Flexible document-processing, indexing, evaluation, or report-generation jobs can be scheduled off-peak. Do not delay urgent user requests solely to obtain a lower rate.

Requests near a pricing boundary: the public pricing page does not specify how to settle every request that spans two pricing windows. Keep both start and end timestamps. Use a conservative reservation and flag an uncertain classification for reconciliation rather than treating request-start time as a documented billing guarantee. Maintain the applicable Chinese holiday calendar instead of hard-coding “not a holiday.”

How to calculate the cost of one request

For a locally calculated token cost, combine validated returned usage with the applicable model’s rate snapshot. This calculation is not, by itself, confirmation of the amount deducted from the provider account:

request cost =
(cache-hit input tokens / 1,000,000 × cache-hit rate)
+ (cache-miss input tokens / 1,000,000 × cache-miss rate)
+ (completion tokens / 1,000,000 × output rate)

The Chat Completions API reference places reasoning_tokens inside completion_tokens_details. Use completion_tokens once in the formula; do not add reasoning tokens again. A missing reasoning breakdown does not mean zero reasoning, but the total completion count can still support the output-cost calculation.

Worked example using deepseek-flash

Assume a hypothetical peak-period request returns 12,000 cache-hit input tokens, 8,000 cache-miss input tokens, and 2,500 completion tokens.

ComponentCalculationCost
Cache-hit input12,000 ÷ 1,000,000 × $0.006$0.000072
Cache-miss input8,000 ÷ 1,000,000 × $0.30$0.002400
Completion2,500 ÷ 1,000,000 × $1.20$0.003000
TotalSum of all three components$0.005472

The same hypothetical token mix at off-peak Flash rates gives $0.002736. These are arithmetic examples, not receipts from live paid requests. Keep full precision in the local records before applying a reporting-rounding policy.

Cache-hit vs. cache-miss billing

DeepSeek context caching is enabled by default. A later request can receive a cache hit when its prefix fully matches a persisted cache-prefix unit from previous work. The cache affects the input-token rate; the model still generates the output normally.

The API reports prompt_cache_hit_tokens and prompt_cache_miss_tokens, whose sum equals prompt_tokens. The official caching guide describes cache hits as best-effort, not guaranteed. Measure the actual split; do not substitute an expected hit ratio for missing measurements.

  • Place reusable instructions or shared context before request-specific content when that structure fits the task.
  • Keep repeated prefixes stable instead of adding changing timestamps near the beginning.
  • Capture returned hit and miss counts; investigate missing fields rather than filling them with zeros.
  • Monitor a sustained rise in cache-miss share, because it can increase input cost.

Log token usage and calculated request cost

A useful billing log should make each request attributable and reproducible without collecting unnecessary content. Record:

  • UTC start and end timestamps, an internal request ID, and an attempt ID for retries.
  • Provider response ID, requested API model, and returned model identifier.
  • An internal user, workspace, project, agent, or feature ID without unnecessary personal information.
  • prompt_tokens, prompt_cache_hit_tokens, prompt_cache_miss_tokens, completion_tokens, and total_tokens; keep optional reasoning_tokens unknown when absent.
  • Peak or off-peak classification, currency, rate-snapshot version, and any pricing uncertainty.
  • Calculated component costs, total local cost, reconciliation status, and the reason for any pending record.
  • HTTP status, sanitized error category, retry count, latency, and budget reservation or settlement identifiers.

Do not log API keys, authorization headers, raw secrets, or personal data. Full prompts and outputs are not required merely to calculate token cost; if they are retained for another legitimate purpose, apply separate access, privacy, and retention controls.

Capture usage from streamed responses

For the direct DeepSeek Chat Completions API, the last chunk before data: [DONE] carries the request’s usage. Setting stream_options.include_usage to true makes earlier chunks contain usage: null; without it, those earlier usage fields are absent. Either way, process the final usage-bearing chunk. The current Chat Completions API reference does not describe a separate usage-only chunk.

{
  "stream": true,
  "stream_options": {
    "include_usage": true
  }
}

Persist that final usage record before closing the request in your ledger. A disconnected client or lost final chunk leaves the local cost unknown; it does not prove that no work was billed. Do not turn usage: null into an empty dictionary and then fill missing counters with zeros.

For a complete stream-reading workflow, see our DeepSeek API streaming guide.

Missing usage is not zero cost

Use a pending state when required counts are missing, malformed, or inconsistent. Validate both identities: prompt_tokens = cache-hit tokens + cache-miss tokens and total_tokens = prompt_tokens + completion_tokens. The statuses below are suggested fields for your local ledger, not fields returned by DeepSeek.

Available evidenceLocal recordBudget action
Complete, consistent counts and verified pricingbilling_status: calculated; record the calculated amountApply the local settlement policy and reconcile with provider records.
Missing or invalid usage, an unexpected model, or uncertain pricingbilling_status: pending_reconciliation; calculated_cost_usd: nullKeep the hold or an equivalent pending exposure. Investigate before releasing funds.
Explicit zero counters in an otherwise valid usage objectA computed zero can be recorded; it is different from missing measurements.Keep the response evidence. Do not treat local arithmetic as provider confirmation.

Python example: validate usage and calculate a local cost

This Python 3.10+ example runs offline with the standard library. It makes no API call, uses no API key, and does not reserve or deduct funds. In an application, pass the parsed response from an existing successful Chat Completions request—or its final streaming chunk—to build_cost_record.

The calculator requires the documented top-level token counts and checks the returned model against the requested canonical model name. It deliberately avoids reconstructing missing counts from guesses or silently mapping an unexpected model to Flash. Pass a verified peak or off_peak period; leave it as None when uncertain. A different SDK response shape needs explicit, tested normalization before using this helper.

"""Offline cost-record example. Makes no API calls and reserves no funds."""
import json
from decimal import Decimal, localcontext
from typing import Any

SNAPSHOT_DATE = "2026-10-16"  # Our verification date, not an effective-date claim.
MILLION = Decimal("1000000")
# USD per 1M tokens: cache-hit input, cache-miss input, completion.
RATES = {
    "deepseek-flash": {
        "off_peak": ("0.003", "0.15", "0.60"),
        "peak": ("0.006", "0.30", "1.20"),
    },
    "deepseek-v4-pro": {
        "off_peak": ("0.022", "0.66", "1.98"),
        "peak": ("0.044", "1.32", "3.96"),
    },
}
COUNT_FIELDS = (
    "prompt_tokens", "prompt_cache_hit_tokens", "prompt_cache_miss_tokens",
    "completion_tokens", "total_tokens",
)


def token_count(value: object, name: str) -> int:
    # bool, float, strings, null, and negative values are not valid counts here.
    if type(value) is not int or value < 0:
        raise ValueError(f"Missing or invalid token count: {name}")
    return value


def validate_usage(usage: object) -> dict[str, Any]:
    if not isinstance(usage, dict) or not usage:
        raise ValueError("Usage is missing, empty, or not an object")
    counts = {name: token_count(usage.get(name), name) for name in COUNT_FIELDS}
    hit, miss = counts["prompt_cache_hit_tokens"], counts["prompt_cache_miss_tokens"]
    if counts["prompt_tokens"] != hit + miss:
        raise ValueError("Prompt tokens do not equal cache hits plus cache misses")
    if counts["total_tokens"] != counts["prompt_tokens"] + counts["completion_tokens"]:
        raise ValueError("Total tokens do not equal prompt plus completion")

    # These nested breakdowns are not needed to calculate the three charges.
    # Validate them when supplied, but never invent a zero for absent reasoning.
    reasoning = None
    for key, field in (("prompt_tokens_details", "cached_tokens"),
                       ("completion_tokens_details", "reasoning_tokens")):
        details = usage.get(key)
        if details is None:
            continue
        if not isinstance(details, dict):
            raise ValueError(f"Invalid breakdown: {key}")
        value = details.get(field)
        if value is None:
            continue
        value = token_count(value, f"{key}.{field}")
        if field == "cached_tokens" and value != hit:
            raise ValueError("Nested cached_tokens conflicts with cache-hit count")
        if field == "reasoning_tokens":
            if value > counts["completion_tokens"]:
                raise ValueError("Reasoning tokens exceed completion tokens")
            reasoning = value
    return {**counts, "reasoning_tokens": reasoning}


def build_cost_record(
    response: object, *, requested_model: str, period: str | None = None
) -> dict[str, Any]:
    """Calculate a local USD cost, or leave it unknown for reconciliation.

    Pass a parsed Chat Completions response or its final streaming chunk.
    period must be verified for this request; leave it None when uncertain.
    This function does not send requests, reserve budgets, or confirm charges.
    """
    record: dict[str, Any] = {
        "billing_status": "pending_reconciliation",
        "currency": "USD",
        "requested_model": requested_model,
        "returned_model": None,
        "provider_response_id": None,
        "pricing_period": period,
        "rate_snapshot_verified_on": SNAPSHOT_DATE,
        "rates_usd_per_1m": None,
        "usage_counts": None,
        "cost_components_usd": None,
        "calculated_cost_usd": None,
        "review_reason": None,
    }
    try:
        if not isinstance(requested_model, str) or requested_model not in RATES:
            raise ValueError("No verified rate snapshot for the requested model")
        if not isinstance(response, dict):
            raise ValueError("No parsed response available")
        record["returned_model"] = response.get("model")
        record["provider_response_id"] = response.get("id")
        if response.get("model") != requested_model:
            raise ValueError("Missing or unexpected returned model; review rate mapping")
        usage = validate_usage(response.get("usage"))
        record["usage_counts"] = usage
        if period not in ("peak", "off_peak"):
            raise ValueError("Pricing period is unverified or crosses a boundary")

        rates = dict(zip(("cache_hit", "cache_miss", "output"),
                         map(Decimal, RATES[requested_model][period])))
        record["rates_usd_per_1m"] = {k: format(v, "f") for k, v in rates.items()}
        with localcontext() as context:
            context.prec = 40
            components = {
                "cache_hit": Decimal(usage["prompt_cache_hit_tokens"])
                             * rates["cache_hit"] / MILLION,
                "cache_miss": Decimal(usage["prompt_cache_miss_tokens"])
                              * rates["cache_miss"] / MILLION,
                "output": Decimal(usage["completion_tokens"])
                          * rates["output"] / MILLION,
            }
            total = sum(components.values(), Decimal("0"))
        record.update(
            billing_status="calculated",
            cost_components_usd={k: format(v, "f") for k, v in components.items()},
            calculated_cost_usd=format(total, "f"),
        )
    except ValueError as error:
        record["review_reason"] = str(error)
    return record


if __name__ == "__main__":
    # Synthetic fields, not a response from a paid test.
    example = {
        "id": "offline-example",
        "model": "deepseek-flash",
        "usage": {
            "prompt_tokens": 20_000,
            "prompt_cache_hit_tokens": 12_000,
            "prompt_cache_miss_tokens": 8_000,
            "completion_tokens": 2_500,
            "total_tokens": 22_500,
        },
    }
    for label, payload in (("complete_usage", example),
                           ("missing_usage", {**example, "usage": None})):
        result = build_cost_record(payload, requested_model="deepseek-flash", period="peak")
        print(json.dumps({"example": label, **result}, indent=2))

The synthetic complete-usage example prints billing_status: calculated with calculated_cost_usd: "0.005472". The missing-usage example prints billing_status: pending_reconciliation with calculated_cost_usd: null. The absent reasoning breakdown remains null; it is not silently reported as zero.

The rate snapshot is dated 2026-10-16, our verification date—not a claim that these prices first took effect that day. Production systems should select the appropriate versioned rates for each request and retain that selection. Do not apply this USD table to a CNY ledger or third-party gateway without the matching pricing rules.

Integration boundary: printing a record is not durable logging, and comparing a cost with a budget is not an atomic reservation. Persist records and reservations in your application’s transactional store. Timeouts, invalid JSON, HTTP errors, and interrupted streams must be handled by the caller; when billable processing or usage remains uncertain, record pending exposure instead of fabricating a zero. Deduplicate repeated delivery of the same usage record so it cannot settle the budget twice.

Implement budget limits inside your application

Do not assume the provider balance enforces a monthly, project, or end-user budget inside your application. The public pricing, balance, usage, and error documentation reviewed does not establish those application-level controls. Check the signed-in platform before relying on an account feature, and implement any additional limits your product requires. The following is a recommended application pattern, not a promise of built-in DeepSeek functionality.

ControlWhat it represents
Provider account balanceThe funds currently reported as available for API calls.
Conservative request estimateA planning amount based on input assumptions, an output cap, and selected rates—not automatically a guaranteed upper bound.
Reserved application budgetFunds held atomically in your own system before work begins.
Locally calculated request costThe result of validated usage and a rate snapshot; it still needs reconciliation.
Pending exposureA request that may have consumed funds but cannot yet be priced or settled reliably.
Historical local spendYour deduplicated, durable ledger by account, user, project, feature, or agent.
  1. Choose the budget scopes. Examples include account, day, month, workspace, user, project, feature, and agent.
  2. Estimate conservatively. Allow for cache misses and capped output. When timing is uncertain, use the model’s peak rates for the reservation. Include system messages, conversation history, tool definitions, and any image input in the input estimate.
  3. Enforce limits, not just estimates. A tokenizer estimate is not a strict upper bound. Enforce input and output limits, bound retries and agent calls, and add a documented safety margin. Each additional API attempt needs its own budget treatment.
  4. Reserve atomically. Use a transaction, conditional update, or equivalent atomic operation so concurrent workers cannot reuse the same available budget.
  5. Reject or downgrade safely. When a reservation fails, block the request, select a cheaper permitted model, reduce its output cap, or defer non-urgent work under product policy.
  6. Settle once. For validated usage and pricing, charge the local scopes and release unused reservation. If the cost exceeds the reservation, record the full cost and flag the overrun instead of clipping it.
  7. Keep uncertain outcomes pending. Missing usage, ambiguous timeouts, or unresolved pricing must not release the reservation as though the request were free. Apply a documented reconciliation and escalation policy.
  8. Add a low-balance stop. Pause nonessential billable work after a confirmed 402 or when provider funds fall below an operational threshold.

Base a critical threshold on the maximum plausible cost of in-flight work, essential recovery traffic, and a monitoring buffer. Because token estimates can differ from returned usage, do not advertise a guaranteed spending ceiling unless the enforced limits and reservation design support it. Alert before the hard stop and review aged pending records.

How to prevent the API balance from running out

  • Check the provider balance on a reasonable operational cadence and after a top-up; do not poll before every high-volume request unless the architecture requires it.
  • Alert on both a fixed remaining amount and estimated runway based on recent burn rate.
  • Cap output with max_tokens and configure thinking mode and reasoning effort intentionally.
  • Limit automatic retries and distinguish retryable server errors from non-retryable billing failures.
  • Attribute spend to users, workspaces, projects, features, and agents so a runaway path is visible.
  • Separate development, staging, and production reporting even if they share one provider account.
  • Schedule eligible batch work during off-peak periods.
  • Monitor the cache-hit ratio and investigate unexpected cache-miss growth.
  • Stop nonessential jobs when the provider balance or internal budget crosses a critical threshold.
  • Keep the master API key on trusted servers; never let end users call DeepSeek directly with it.

Provider balance checks are snapshots, not locks. Combine provider-level balance monitoring with atomic application reservations and visibility into pending exposure. A low-balance alert alone cannot stop simultaneous workers from spending.

How to fix 402 Insufficient Balance

The official error-code reference defines HTTP 402 as insufficient balance. This is different from a rate-limit error. Stop blind retries and check the account before resuming billable work.

  1. Capture the HTTP status and a sanitized error body, without recording the API key.
  2. Confirm that the key belongs to the intended account and environment.
  3. Call GET /user/balance; inspect is_available and the relevant currency entry in balance_infos.
  4. Review recent workloads and independently confirmed grant or account adjustments. Do not infer grant expiration solely from a lower balance.
  5. When funds are needed, use the official Top Up page and confirm the funds appear in the platform or balance response.
  6. If a completed top-up is still missing, check the signed-in account and official support route rather than assuming a fixed processing time or repeatedly paying again.
  7. Resume gradually after both provider funds and application budgets permit it; monitor the initial requests before releasing the backlog.
StatusOfficial meaningAppropriate first action
401Authentication failed, such as a wrong API key.Verify the key and account configuration.
402Insufficient balance.Check the balance, pause billable work, and use the official top-up flow if needed.
429Requests are being sent too quickly.Pace requests and apply controlled backoff.
500Server error.Retry after a brief wait and escalate if it persists.
503Server overloaded.Retry after a brief wait.

A 402 needs a balance investigation, while 429 needs request pacing and rate-limit handling. For other response codes, use the DeepSeek API error guide. Retrying the same insufficient-balance request cannot restore funds.

Why the free DeepSeek app does not provide API balance

The consumer chat product and developer API are separate access paths. DeepSeek’s official download page advertises free consumer access; that does not establish a funded developer balance. Programmatic requests follow the API platform’s own pricing and balance rules. Our guide to what is free in DeepSeek explains the distinction.

Do not assume a new-account credit, recurring free API quota, or transfer from consumer access. Use the funds actually reported for your account. A valid balance response showing zero granted balance means no active grant is reported; a missing field or failed balance request means the information is unknown, not zero.

Reconcile local cost records with the provider balance

Reconcile each currency separately using independently recorded account movements, not just changes in the granted-balance field:

expected closing balance =
opening balance
+ confirmed top-ups
+ confirmed new grants
+ confirmed credits or other additions
- locally recorded usage charges
- independently confirmed expirations or other non-usage deductions
  1. Store opening and closing provider balance snapshots with timestamps and currency.
  2. Aggregate deduplicated local usage costs for a matching period, while keeping unresolved requests visible as pending exposure.
  3. Add confirmed top-ups, new grants, and other verified credits. Subtract only independently confirmed non-usage deductions.
  4. Compare the expected closing balance with the reported closing balance, allowing for the timing of in-flight work and account updates.
  5. Investigate missing streaming usage, unlogged workers, duplicate local entries, stale rates, model mismatches, pricing boundaries, and unresolved requests.
  6. Close the period only under a documented tolerance and review policy; do not erase unexplained differences by assigning pending requests a zero cost.

A falling grant balance is not a second charge. When usage consumes granted funds, that reduction is already represented by the usage cost. Subtracting it again as an “expired grant” would double-count the loss. If the balance endpoint alone cannot explain an adjustment, keep it unresolved and consult the account records or official support.

Retain request IDs, model identifiers, timestamps, usage, currency, and rate versions without storing unnecessary prompts or responses. Balance snapshots help check aggregate spending, but they do not reliably identify the cost of one concurrent request. Provider records—not an assumed zero in a local log—remain the basis for resolving an unexplained deduction.

Official sources checked