AI feature cost attribution works only when you combine three layers: separate deployments per feature, tags or identities that reach the billing data, and token logs carrying a feature ID in your application. The Azure OpenAI or Amazon Bedrock bill knows the model, token type and resource, but not the feature. Reconciling the logs to the bill is what turns token counts into feature costs you can defend.
What the bill provides and what it lacks
Azure OpenAI and Bedrock charges: meters, usage types, tags explains how Azure meters and Bedrock usage types are built. For feature attribution, what matters is that the bill aggregates by model, token type, deployment type and resource, and in CUR by usage type per hour or day. It never shows an individual request, a feature or a customer. You either build that information into the structure (layers 1 and 2) or log it yourself (layer 3).
Layer 1: separate deployments per feature
In Azure, give each feature its own deployment or its own Foundry project. Cost analysis can split a Foundry resource's cost across its model deployments and filter by deployment tags. Microsoft states that every Foundry project automatically gets a project tag on its usage; this is in preview and covers only models sold by Azure, not Marketplace models. If you need feature costs that do not depend on a preview, use a separate Foundry resource per feature.
In AWS, create an application inference profile per feature and call its ARN instead of the model ID. The profile's tags flow into Cost Explorer and CUR:
aws bedrock create-inference-profile \
--inference-profile-name support-summary \
--model-source copyFrom={foundation_model_or_system_profile_arn} \
--tags key=feature,value=support-summary key=costcentre,value={cost_centre}
Profiles work with InvokeModel and Converse on bedrock-runtime. The Responses and Chat Completions APIs reject them with a 400 error; for those, use Projects on bedrock-mantle, which can span several models. Each profile belongs to exactly one model, so the number of profiles grows with models times features.
The price of this layer: capacity and quotas are spread across more deployments, and provisioned throughput dedicated to one feature sits idle sooner than a shared pool.
Layer 2: tags and identities
In AWS, tags on resources, profiles and projects only count once activated as cost allocation tags in the management account, and they are not retroactive. A backfill of up to twelve months helps only if the tag was already on the resource. In Azure, tag inheritance, once enabled, copies subscription and resource group tags onto usage records from the current month.
Bedrock also records the calling IAM identity. In a new CUR 2.0 export that includes identity data, it appears in line_item_iam_principal, and role or session tags appear with the prefix iamPrincipal/. If each feature runs as its own service with its own IAM role, you get the feature split without code changes. If every feature goes through one shared gateway role, you only see the gateway.
For tag values: a small set of stable feature codes, no customer IDs, no personal data. Tags are visible in billing data to everyone allowed to read costs.
Layer 3: token logs with a feature ID
For attribution per request, or when many features share one gateway, log every call. These fields are enough, with their source for each provider:
{
"ts_utc": "{request start in UTC}",
"feature_id": "support-summary",
"provider": "azure or aws",
"deployment_or_profile": "{deployment name or profile ARN}",
"model": "{model}",
"deployment_type": "{GlobalStandard, DataZoneStandard, ...}",
"input_tokens": "{usage.prompt_tokens or usage.inputTokens}",
"cached_input_tokens": "{prompt_tokens_details.cached_tokens or usage.cacheReadInputTokens}",
"cache_write_tokens": "{prompt_tokens_details.cache_write_tokens (GPT-5.6 and later) or usage.cacheWriteInputTokens}",
"output_tokens": "{usage.completion_tokens or usage.outputTokens}",
"reasoning_tokens": "{completion_tokens_details.reasoning_tokens}",
"attempt": "{1 for the first call, 2 or more for retries}",
"status": "{ok, error, cancelled}",
"request_id": "{provider request ID}"
}
Microsoft bills reasoning tokens as output tokens; in its response example they are part of completion_tokens, so do not count them twice.
Bedrock can do part of this for you. With requestMetadata (Converse) or the X-Amzn-Bedrock-Request-Metadata header (InvokeModel) you attach up to 16 key-value pairs that land in the model invocation logs. Those logs are off by default, apply per region and can contain prompts. The metadata does not appear in Cost Explorer or CUR.
In Azure, API Management's llm-emit-token-metric policy sends token counts as metrics to Application Insights, with up to five custom dimensions such as a feature header. API Management limits each dimension to 100 values and each namespace to 1,000 active time series; beyond that, data is discarded silently. Customer IDs as a dimension would break the metric.
Reconciling logs to the bill
Logs are an estimate; the bill is the evidence. So distribute billed cost by logged share instead of multiplying tokens by your own price list:
C(m) effective cost of meter or usage type m in the month (bill)
Q_bill(m) billed quantity of m, converted to tokens
Q_log(f,m) logged quantity of feature f on m
Cost(f) = sum over m of C(m) × Q_log(f,m) / Q_bill(m)
Unallocated = sum of all C(m) − sum of all Cost(f)
Coverage(m) = sum over f of Q_log(f,m) / Q_bill(m)
- Aggregate logs per day in UTC, model, token type and deployment type, the way the bill does.
- Map each combination to a meter or usage type and convert 1K and 1M units.
- Check coverage per meter. Well below one means missing logs: aborted streams, batch jobs, other applications on the same resource. Above one means you log calls that were not billed, or count twice.
- Distribute only token meters with this key. Allocate provisioned capacity (PTU, model units) by token share on that specific deployment only up to its measured utilisation, and report the rest as idle.
- Leave the remainder as unallocated and version the rule with month and data cut-off.
AWS itself states that CUR carries no request ID per line. You can reconcile only per model and usage type, with the logs as detail underneath.
Embeddings, vector stores and other shared costs
Not everything belongs to one feature. Building embeddings for an index several features use is a shared cost; embedding a single search query belongs to that feature directly. Vector stores often cost the same regardless of load: Azure AI Search on the Dedicated model bills search units (replicas times partitions) per hour and stops only when deleted, and vectorisers are billed at the rate of the model used, for example as Azure OpenAI cost. In OpenSearch Serverless, the minimum OCU setting per collection group sets the baseline.
Write down a rule for such items: share of queries, share of index volume, or central platform cost. Multi-tenant SaaS cost allocation shows how to choose a key for each shared component.
Which layer answers which question
| Situation | Layer | Reason |
|---|---|---|
| Few features, each its own service | 1 and 2 | Close to the bill, no log pipeline needed |
| Many features behind one gateway | 3 with reconciliation | Profiles per model and feature become unmanageable |
| Shared provisioned throughput | 3 for shares, idle shown separately | Capacity has no feature |
| Partner models via Azure Marketplace | 1 (own resource) or 3 | No project tag |
| Setting a feature's price | 3 with reconciliation, remainder explained | The basis must match the bill |
| Cost per customer | 3 with a pseudonymous ID in logs only | Tags and metric dimensions are unsuitable |
For cost per customer, connect the feature figures to the metric in Cloud cost per customer; whether AI spend belongs in cost of revenue is covered in Cloud costs and SaaS gross margin.
Limits
Token logs do not reflect discounts, commitments, batch prices or capacity, which is why you distribute billed amounts rather than list prices. Aborted streams can leave token counts missing. Tags, profiles and identity data only work from the moment they are set up. If logs make individual employees identifiable, for example in internal tools, agree data protection and works council questions with your advisers before you log; this article is not legal advice.
Where Costfluent fits
Costfluent reads Azure and AWS billing data through read-only connectors and assigns it to teams, products or cost centres with allocation rules, based on account, resource and tags. Shared costs are split without losing or double-counting money, and unallocated spend stays visible; the result is showback. Costfluent does not read token telemetry or invocation logs, so the per-request split stays in your log pipeline.
Sources and method
Checked on 10 October 2026: Microsoft Foundry: plan and manage costs, Azure OpenAI prompt caching, Azure OpenAI reasoning models, API Management llm-emit-token-metric, Azure tag inheritance, Azure AI Search costs, Bedrock application inference profiles, Bedrock Projects, Bedrock IAM principal attribution, Bedrock request metadata, Bedrock model invocation logging, Bedrock TokenUsage, AWS CLI create-inference-profile, AWS CUR 2.0 line item columns, AWS cost allocation tag backfill, OpenSearch Serverless capacity. The layer model, formula and decision table are Costfluent recommendations, not legal or accounting advice.



