Technical Guide

    Comparing cost per use case across OpenAI, Anthropic, and Amazon Bedrock on one ledger

    To compare LLM cost per use case across providers, record every model request in one ledger with a use case identifier attached at the point of call. Store token counts by type, the provider, the model version, and the region. Compute cost from a versioned price table, and reconcile ledger totals to provider invoices and cloud billing exports. Treat the result as an attributable record, not a verdict on which provider is better.

    Why the ledger is a data-modeling problem

    Teams running production workloads on OpenAI, Anthropic (direct), and Amazon Bedrock receive usage and billing data in different units, schemas, and granularities. One provider may report usage per request, another per day or per project, and a cloud bill adds its own line items and timing. None of these records knows what business use case produced the call.

    The common mistake is to treat this as a pricing comparison and build a spreadsheet of per-token rates. Rates are only one input. The harder work is defining a record structure that every request can be written into, so that cost per use case becomes a query over your own data instead of a reconstruction from three vendors' reports.

    A useful ledger answers three questions for any request: which use case generated it, which model under which provider served it, and what policy applied. If the ledger cannot answer all three, cost figures will not hold up when finance, security, or an auditor asks for the basis.

    Define the minimum record schema

    Start with one row per model interaction. Keep the schema provider-neutral, and keep provider-specific detail in a raw payload field so nothing is lost when normalizing. The following fields are the practical minimum.

    • Use case identifier: A required value from a controlled list, plus an explicit unattributed value for requests that arrive without one.
    • Provider, model, and version: Store the exact model version string returned or requested, since pricing and behavior can change between versions.
    • Token counts by type: Input, output, cached, and batch tokens as separate columns, not a single total.
    • Computed cost and price reference: The calculated amount and the identifier of the price table version used to compute it.
    • Policy decision: The outcome applied to the interaction, such as allow, redact, or block.
    • Timestamp, region, and request key: UTC time, the serving region, and a request identifier that can be matched to provider-side records.

    Tag each request with a use case identifier at the point of call

    Attribution that is added after the fact is a guess. The identifier has to be attached when the request is made, by the calling service or by a shared component that every call passes through. Reconstructing it later from API keys, accounts, or project names works only when each of those maps to exactly one use case, which rarely holds in shared platforms.

    Provider-side mechanisms, where a provider offers them, such as tags, metadata fields, or separate inference profiles, are useful as a second copy of the identifier. They help when matching against provider exports. They should not be the only source, because each differs in how it is set and reported, and the ledger needs one consistent value regardless of provider.

    Decide in advance what happens when the identifier is missing. Rejecting the request is the strictest option. Recording it under an explicit unattributed value and reporting the unattributed share is the more common one. Either way, a missing tag should be visible in the data, not silently absorbed into a default.

    Normalize token and pricing differences

    Normalization has two parts: units and prices. For units, map each provider's token categories onto your schema's columns. Cached input, batch processing, and standard input are billed differently, so collapsing them into one count makes computed cost wrong in a way that is hard to detect later. Where a provider does not report a category, store zero or null deliberately and document which.

    For prices, keep an effective-dated price table keyed by provider, model version, region, and pricing mode. Computed cost should reference the row that applied when the request was made. This matters for model version changes, regional price differences, caching and batch discounts, and any change in published rates. Recomputing history with today's prices is the most common reason ledger totals drift from invoices.

    Provisioned or reserved capacity needs separate handling. Its charge accrues over time rather than per token, so there is no per-request price to compute. Record it as a period-level cost and allocate it to use cases by a stated rule, such as share of tokens served. Mark allocated amounts as allocated, so they are never confused with metered amounts.

    Reconcile ledger totals against invoices

    A ledger is defensible only if it ties to what was actually billed. Reconcile on a fixed cadence, by provider, billing period, and model. Compare ledger-computed cost with the invoice or cloud billing export for the same period, and compare ledger token counts with provider-reported usage where available.

    Expect differences and classify them. Typical causes are timing at period boundaries, missing price table rows, requests that never reached the ledger, retries counted differently, and charges that have no per-request form, such as provisioned capacity. Each variance should end up in a named category with an owner, not in a plug figure.

    Track two health measures alongside the totals: the share of spend under the unattributed use case value, and the share of the invoice explained by ledger records. If either moves, the tagging or the price table has changed, and cost per use case figures should be treated with caution until it is understood.

    Limits of comparison, and the role of the execution path

    Cost per token is not cost per outcome. Two models can serve the same use case with different quality, latency, and policy results, such as more blocked or redacted interactions or more retries. A ledger can place those measures beside cost, but it cannot make a lower number mean a better choice. Keep comparisons scoped to the same use case and the same workload, and state what was held constant.

    Multi-step and agentic workloads add a second limit. One user action may trigger several model calls and tool calls. Per-interaction attribution records each of them accurately, but grouping them under one business action depends on the application propagating a shared identifier. Without that, the ledger holds correct rows that cannot be assembled into a single transaction.

    The execution path is the one place where every request passes regardless of provider, so it is a natural point to attach consistent per-interaction metadata. Trussed enforces policy in the execution path, applying allow, redact, or block at runtime rather than reviewing after the fact, and produces audit-ready evidence from that enforcement. A ledger can reference that evidence by interaction, so each cost record is tied to the policy decision that applied. Trussed operates at the level of individual interactions and tool calls. It does not provide transaction-level attribution across tasks or agents.

    One ledger, four stages

    Tag

    Attach a use case identifier to every request at the point of call.

    Record

    Write one normalized entry per interaction, whichever provider served it.

    Normalize

    Map provider token categories and price variables to one structure.

    Reconcile

    Match ledger totals to invoices and cloud billing exports.

    Tie each interaction to a policy decision

    See how enforcement in the execution path produces audit-ready evidence that a usage ledger can reference.

    See How Evidence Is Produced