Research-backed calculator guide

AI API Subaccount Usage Tracking: Isolate Customers Without Losing Parent-Account Control

A provider-neutral method for tracking AI API usage by customer subaccount, rolling it up to parent totals, and exporting a defensible cost ledger.

● First-party sources checked▧ Original calculation examples◌ Estimate, not a vendor quote

Quick answer

AI API subaccount usage tracking is the practice of assigning every billable model call to a customer, workspace, or business unit below one controlled parent account. The reliable design is not “one API key equals one invoice.” It is a four-part ledger: a stable subaccount identifier, the provider usage response, the price version used for calculation, and a reconciliation record that ties all child rows back to the parent bill.

Keep the provider credential and spending authority at the parent level when that is your control requirement. At the application boundary, attach a customer or subaccount ID before the request starts. At response time, store the provider request ID, model, input units, output units, cached units where applicable, status, and timestamp. Calculate a child cost from the recorded usage and a dated rate card. Then compare the sum of child costs with the parent-level usage or invoice total, while showing unallocated, tax, credit, and rounding lines separately.

That approach lets you answer three different questions without confusing them:

  1. Who caused the request? The application’s authenticated customer or subaccount.
  2. What did the provider meter? The provider response’s usage fields and other billable units.
  3. What should be charged or reported? Your versioned allocation rule, which may include markup, included allowance, taxes, or shared overhead.

The distinction matters because a provider’s account hierarchy and your customer hierarchy are not always identical. A provider may expose projects, workspaces, keys, or subaccounts, while your product identifies tenants, plans, and seats. Treat those as separate dimensions and join them with a mapping table instead of assuming the provider key is the customer record.

What to capture for each subaccount request

Start with an immutable request ledger. A minimum row should include:

  • event_id: your unique idempotency key for the completed usage event.
  • parent_account_id: the controlled provider account or internal billing owner.
  • subaccount_id: the customer, tenant, workspace, or business unit that initiated the request.
  • provider_project_or_key_id: the provider-side scope, if available. Store it as evidence, not as a substitute for subaccount_id.
  • provider_request_id: the provider’s request or response identifier.
  • model and provider: the actual service selected, including fallback provider if routing changes.
  • usage_input, usage_output, and other units: integers or decimals in the provider’s stated unit.
  • usage_total: either a provider-reported total or a derived total with the derivation recorded.
  • rate_card_version: the dated price schedule or internal rate identifier used.
  • raw_cost, shared_cost, customer_charge, and currency.
  • status, created_at, and settled_at.

For token-based models, do not collapse everything into one total_tokens number too early. OpenTelemetry’s GenAI semantic conventions distinguish input and output token counts and also describe cache-creation, cache-read, and reasoning-output fields.[3] Those dimensions let finance explain why two calls with the same visible output can have different costs. They also make a later provider migration less destructive because the ledger retains the original meter rather than only a converted dollar amount.

Use a stable internal ID, not an email address, as the subaccount key. Emails change, can be reused, and may expose personal information in exports. If a customer can have multiple workspaces, make the hierarchy explicit: customer_id, workspace_id, and optionally end_user_id. Decide which level owns the bill before production traffic arrives.

Parent control and child attribution are different controls

Parent-account control governs credentials, permissions, maximum spend, provider limits, and emergency shutdown. Child attribution answers which customer consumed the capacity. You can keep the first at the parent and implement the second in your gateway or service layer.

The safest request flow is:

  1. Authenticate the caller against your application.
  2. Resolve the caller to one authorized subaccount_id.
  3. Create a request context containing that ID and a generated event_id.
  4. Send the provider request through one instrumented client or gateway.
  5. Read usage from the provider response, including non-token meters such as image units, seconds, pages, or searches when relevant.
  6. Write the event exactly once, or upsert by event_id if retries can repeat delivery.
  7. Aggregate child rows into a daily and monthly rollup.
  8. Compare the rollup with provider usage and the parent invoice before issuing a customer statement.

An observability system can help propagate the customer identity through nested spans, but it is not the billing ledger by itself. Langfuse documents propagating a userId across observations so that usage cost can be aggregated by user, and it recommends calling the propagation early enough to cover the trace.[1] Use the same principle for a subaccount context: set it at the start of the request and carry it through retries, tool calls, model calls, and fallback branches.

Do not let clients submit an arbitrary tenant ID in a header and trust it. Resolve the ID server-side from the authenticated session or API key. If you accept a client-supplied correlation ID, treat it as a trace field and validate it against the authenticated account.

Build the cost formula before you build the dashboard

A useful child cost formula is:

raw_cost = Σ(quantity_i × rate_i) + fixed_request_fees

Here, each quantity_i is a provider meter such as input tokens, output tokens, cached input tokens, audio seconds, or image units. Each rate_i must carry a unit, currency, effective date, and source. If your provider reports an inclusive input total plus a cached subset, convert it into non-overlapping buckets before multiplying. Otherwise, the cached tokens may be counted twice.

Langfuse describes the same accounting hazard in its usage model: usage details are separate, non-overlapping buckets, and total is the sum of those buckets rather than another bucket to add.[2] That is a practical rule for any home-grown ledger. Store the provider’s raw payload for audit, but store normalized exclusive quantities for aggregation.

Then separate your reporting layers:

  • Raw provider cost: what the usage and rate card imply before your commercial rules.
  • Allocated shared cost: gateway, monitoring, or reserved-capacity cost assigned by a stated rule.
  • Customer charge: raw cost plus markup, minimum fee, or overage under your contract.
  • Parent invoice variance: the difference between your attributable total and the provider’s invoice or usage export.

A customer-facing invoice should not silently mix these layers. If you add a 20% markup, label it as markup. If you distribute a $50 shared gateway cost by each tenant’s share of raw usage, label the allocation basis and retain the original $50.

Worked cost example

Assume one parent account serves two subaccounts during a monthly period. The following is an illustrative calculation, not a vendor quote. The assumed rates are deliberately generic: $2.00 per 1,000,000 input tokens, $8.00 per 1,000,000 output tokens, and $0.50 per 1,000,000 cached-input tokens. The example treats cached input as a separate exclusive bucket, so ordinary input excludes cached tokens.

StepInput or assumptionCalculationOutput
1. Identify childsub_acmeEvery settled event mapped to sub_acme1 customer ledger slice
2. Normalize usage8,000,000 input; 2,000,000 output; 1,000,000 cached input tokensCached bucket is exclusive; ordinary input remains 8,000,000Three billable quantities
3. Apply illustrative ratesInput $2.00/M; output $8.00/M; cached $0.50/M8×$2.00 + 2×$8.00 + 1×$0.50$32.50 raw cost
4. Add commercial rule10% markup, if the contract permits it$32.50×10%$3.25 markup
5. Customer statementRaw cost plus markup$32.50 + $3.25$35.75 customer charge
6. Parent roll-upsub_acme $32.50 + sub_beta $17.50 + $2.00 unallocated retry reserveSum child and explicitly unallocated lines$52.00 parent ledger total

The $2.00 retry reserve is not assigned to sub_acme merely because it occurred near one of its requests. It should be assigned only if your retry policy says failed or duplicate attempts belong to the initiating customer. Otherwise, keep it in a separate exception bucket until reconciliation resolves it.

The important output is not the dollar figure by itself. It is the chain of evidence: the subaccount mapping, exclusive usage quantities, rate-card version, formula, and exception line. Change the rates or traffic and the calculation changes; the method remains inspectable.

Reconcile child totals to the parent account

Run reconciliation on a fixed cadence, such as daily for operational alerts and monthly before invoices. Compare at least four values:

parent_observed = child_attributed + unallocated + shared_allocations + adjustments

The parent observed value may come from a provider usage export, invoice, or account-level usage endpoint. It may not equal your child total on the first pass because of timing windows, taxes, credits, minimums, rounding, or meters your application did not capture. Do not force the numbers to tie by changing a customer’s usage. Post a named variance.

Useful reconciliation fields include the reporting window in UTC, provider account scope, export generation time, provider currency, your rate-card version, and the variance reason. A row marked pending_provider_export is more honest than a zero that looks reconciled.

Watch for these failure modes:

  • Missing attribution: a background job calls the model without a customer context.
  • Identity drift: a workspace is renamed but historical rows use the mutable name.
  • Double counting: a retry writes both the original and replay as billable without an attempt policy.
  • Inclusive buckets: cached or reasoning tokens are added on top of an already inclusive total.
  • Fallback mismatch: the application records the requested model, not the model that served the response.
  • Late usage: streaming or asynchronous jobs settle after the invoice cutoff.
  • Shared work: a system prompt, batch job, or safety check benefits many tenants and needs an allocation rule.

Create exception reports for each category. Observability traces help you find missing context, while the ledger and reconciliation file remain the financial evidence.

Export a customer-ready usage statement

A useful export has one summary row per subaccount and a drill-down file for request-level evidence. The summary can show period, customer ID, request count, input units, output units, other units, raw provider cost, shared allocation, markup, credits, and amount due. The drill-down should include event IDs and timestamps, but redact prompts, responses, secrets, and personal data unless the contract and privacy controls permit them.

Keep the provider invoice separate from the customer invoice. The former is a vendor document; the latter is your commercial statement. Link the two through a reconciliation batch ID and preserve the rate card used. If a customer disputes a charge, you can reproduce the statement without asking the provider to reconstruct historical prices.

For a broader monthly model, use the AI agent development cost estimator to include implementation and operating assumptions. Compare the estimate with actuals using the AI API invoice reconciliation calculator, and use the AI observability ROI calculator when deciding how much instrumentation and retention to fund.

Run your scenario

Turn this framework into an editable estimate.

Use dated, source-linked assumptions and see cost per request, successful task and month.

AI agent development cost estimator

FAQ

Can I track usage by customer without creating a provider subaccount for every customer?

Yes. A gateway or application ledger can attach a server-resolved subaccount_id to each provider request even when every request uses one parent credential. This gives you customer attribution and internal billing, but it does not automatically create provider-side isolation, independent provider limits, or separate vendor invoices. Use provider subaccounts or projects when those controls are required, and retain your own customer mapping because the two hierarchies may still differ.

Should each customer receive a separate API key?

Only when the security, quota, or operational requirement justifies it. Separate keys can narrow blast radius and simplify attribution, but they add rotation, storage, and lifecycle work. A parent credential with server-side tenant resolution can be adequate for a managed SaaS integration. Never expose the parent secret to customers, and never use a customer-provided key label as proof of entitlement.

What if the provider reports only aggregate organization usage?

Capture usage at the request boundary before aggregation. Store the customer ID, request ID, model, response usage, and rate-card version in your ledger, then reconcile your child sum to the provider’s aggregate report. If the provider gives no request-level usage, record that limitation and use a documented allocation estimate rather than presenting the estimate as a vendor-confirmed customer charge.

How should cached and reasoning tokens be handled?

Follow the provider’s usage semantics and store mutually exclusive buckets. If a response reports an inclusive prompt total and a cached subset, subtract the subset before calculating ordinary input. If reasoning output is reported separately but included in output, do not add it again. Preserve raw fields alongside normalized fields so the transformation can be audited. The OpenTelemetry GenAI vocabulary provides distinct names for input, output, cache, and reasoning usage fields, but provider payloads still need to be interpreted correctly.[3]

How often should I reconcile a subaccount ledger?

Use two cadences. Reconcile daily or hourly enough to alert on runaway spend and missing attribution. Reconcile at the provider’s invoice or usage-export boundary before customer billing. The exact cadence depends on provider settlement latency and your invoice terms. Always store the reporting window and cutoff time; otherwise a correct late event can look like a discrepancy.

Is an observability platform the same as a billing system?

No. Observability is excellent for tracing context, finding failures, and aggregating operational metrics. A billing ledger needs idempotency, versioned rates, invoice-period close rules, adjustments, and an audit trail. You can feed the ledger from traces, but keep a durable financial record and a reconciliation process outside a dashboard view.

Limitations and assumptions

This method does not assume that every AI provider offers native subaccounts, customer-level invoices, or request-level cost exports. Provider fields and settlement windows vary, and some products meter requests, seconds, pages, images, characters, or reserved capacity rather than tokens. The illustrative rates above are assumptions for showing the arithmetic, not current vendor prices. Replace them with a dated provider rate card or a contractual rate before using the formula for a quote.

The article also does not prescribe a particular tax treatment, markup, revenue-recognition policy, privacy retention period, or customer contract. Those rules belong in your finance and legal review. The safest general rule is to show what the provider measured, what your allocation policy assigned, and what your customer agreement charges as separate layers.

Primary sources checked

Pricing and product behavior can change. These sources support the time-sensitive claims in this guide; verify current provider terms before committing spend.

  1. Langfuse User Tracking
  2. Langfuse Token and Cost Tracking
  3. OpenTelemetry GenAI semantic conventions

About the Author

Zunair Ali Syed is a doctoral researcher in Management Sciences at Minhaj University Lahore and a research consultant with experience in academic research and editing since 2011. He runs QuickEduHelp, with professional interests in digital learning, research methods, and evidence-based academic support.