tags you attach. Vantage splits each matching cost row into enriched rows by token share and adds your tags to each row. This surfaces spend the provider bill never itemized, so you can filter and group it in Cost Reports, Virtual Tags, Budgets, and Cost Alerts. Because you emit the telemetry yourself, this works with or without an AI gateway, even when applications share one API key the bill cannot break apart.
The Custom LLM Enrichment integration enriches costs for Vantage’s native model-provider integrations: OpenAI, Anthropic, AWS Bedrock, Google Cloud (Vertex AI Gemini and Marketplace Claude), and Azure. You deliver one telemetry stream in the Token Cost Allocation Specification, a single, provider-agnostic schema, and Vantage routes each record to the matching provider’s costs.
Custom LLM Enrichment is complementary to Managed AI Tags: Managed AI Tags normalize the fields your providers already report into a shared vntg:ai: schema, while Custom LLM Enrichment enriches costs with per-request dimensions the provider bill leaves out. Enriched rows also carry vntg:ai: tags (including gateway-derived keys such as vntg:ai:endpoint and vntg:ai:service_tier) as described in Enrichment Tag Reference.
tags you choose to emit. Vantage does not collect or store your prompt or completion content, and it is never written to a Vantage-owned artifact. This data is not used to train any models.How It Works
Your application (or the gateway in front of it) emits one JSON record per LLM request in the Token Cost Allocation Specification. You write those records to an S3 bucket you own, and Vantage joins them to your provider costs during that provider’s cost ingestion. See How LLM Enrichment works for the shared indexing, join, split, and tag pipeline.How Telemetry Matches Provider Costs
Provider bills typically aggregate many requests into token-usage line items, so Vantage does not match one telemetry record to one provider request. Instead, Vantage groups your records into daily usage buckets and joins those buckets to compatible provider cost rows. Every provider uses the following base fields. The first four form the initial match;resource_account_id then scopes the result to the correct account.
provider_region, operation, and inference_scope are optional qualifiers rather than requirements. When your telemetry omits one, Vantage treats it as a wildcard that matches any value on the cost side, and it matches exactly qualified telemetry first so the wildcard only absorbs costs that nothing else claimed. Sending these fields produces more precise attribution when you run the same model across Regions, inference profiles, or streaming and non-streaming calls.
How Cost Rows Are Split
Vantage splits each matching provider cost row into enriched rows, allocated proportionally by token share. Splits are additive, so the enriched rows always reconcile to the original total: usage your logs do not cover stays on a leftover row, and cost rows with no matching usage pass through unsplit. Enabling enrichment never changes your totals.How Cost Splitting Works
Data Freshness and Backfill
Enrichment runs as part of each provider’s existing cost ingestion, so it follows that provider’s refresh cadence. Recent days are reprocessed within a rolling three-day window so late-arriving logs are picked up. See the provider data refresh documentation for per-provider timing. A billing period is enriched whenever it is processed while an active source exists, for as long as the matching logs remain in your bucket. Late-arriving logs for recent days are picked up automatically within the rolling three-day window. For older periods, Vantage re-enriches a day when the set of log objects for that day changes (files are added or removed) or when a full rebuild is triggered; replacing the contents of an existing object under the same key does not, on its own, re-trigger enrichment. Re-enrichment reads the already-normalized cost data, so it does not require a full cost re-import.Prerequisites
Before you begin, make sure:- An active cost integration exists for at least one supported provider: OpenAI, Anthropic, AWS, Google Cloud, or Azure.
- An active AWS integration (cross-account IAM role) exists for the account that owns the telemetry bucket. Vantage reads the bucket through this role, so it is required even when the costs you enrich come only from OpenAI, Anthropic, Google Cloud, or Azure.
- You have an S3 bucket you own where you write (or will write) your telemetry.
- You have a Vantage Organization Owner or Integration Owner role. See Role-Based Access Control.
Set Up Custom LLM Enrichment
Setup has two steps: emit your telemetry in the common schema to S3 and connect the source in Vantage, where you grant Vantage read access to the bucket and then review which providers Vantage detected. If you don’t already produce these logs, the cold-start demo below turns an OpenAI or Anthropic API key into spec-conformantYYYY/MM/DD/*.jsonl.gz records you can deliver to S3, a fast way to see enrichment work before you instrument production traffic.
Step 1: Emit Telemetry in the Common Schema
Records follow the Token Cost Allocation Specification. Write one JSON object per request as newline-delimited JSON (JSONL), gzip-compressed, under a date-partitioned path:- Use the request timestamp’s UTC date for the
YYYY/MM/DDpartition. - Place the logs at the bucket root or under any prefix (subfolder); keep the
YYYY/MM/DDdate structure at the end of the path. - Write one record per line; do not wrap records in an outer JSON array.
- Batch many records into larger gzipped files rather than writing one object per request.
- Vantage reads these logs from the connected bucket when importing provider cost data; logs are not pushed directly to Vantage.
tags and top-level metadata become cost dimensions, and Record validity covers what makes a record count.
Core Fields
These fields are required on every record.Accepted provider values
Accepted provider values
provider to the identity that matches your cost integration.gpt-5.2-2025-12-11) while your logs may use dated or undated names (gpt-5.2); Vantage prefers the dated form and normalizes undated names to match.Usage Fields
Theusage object is required. At least one field below must be a positive integer; no single field is always required, so include the counts that describe the request.
non_cache_input_tokens, uncached_input_tokens, and input_tokens all resolve to the same input token kind, so you do not need to send more than one. When neither explicit uncached field is present, Vantage derives uncached input as:
Optional Fields
These fields are optional. Include the ones present on each request to improve matching and add allocation dimensions.resource_account_id is recommended when one bucket carries logs for multiple integrations of the same provider.
Tagging Guidance
These rules govern how yourtags and top-level metadata become cost dimensions, and which values to keep out of tags.
- Top-level
service_tier,is_batch,provider_region,endpoint,api_key_id,operation, andinference_scopevalues override fields with the same names insidetags. resource_account_idmust be top-level and cannot be supplied throughtags.- To signal batch processing, set
service_tiertobatchrather than sendingis_batch. Both are accepted for matching, but onlyservice_tieris surfaced as a tag you can group and filter on;is_batchis used for matching and then dropped. - For Anthropic and Google Cloud Marketplace Claude, set
tags.context_windowortags["anthropic:context_window"]to0-200kor200k-1Mwhen you know the request’s context window. This value participates in matching; other custom tags do not. - Keep
request_id,provider_request_id,flow_run_id, and similar request identifiers out oftags, since they are high-cardinality and are not used as allocation dimensions. - Avoid dimensions with very high cardinality or personally identifiable information (for example, email addresses or conversation identifiers) unless operationally necessary.
Record Validity
For a record to be counted, it must describe a successful request with usage Vantage can match to your costs. A record is skipped when:- A required field (
event_id,timestamp,provider,model, orusage) is missing, or thetimestampis blank or cannot be parsed. - The
provideris blank or not a supported value, or themodelis blank or cannot be matched to your provider cost data. - The
statusis set to anything other thansuccess(omit it or leave it blank for successful requests). - No
usagefield contains a positive integer.
Step 2: Connect the Source in Vantage
In Vantage, go to the Integrations page and, under LLM Enrichment, add Custom LLM Enrichment, then select the S3 bucket that holds your telemetry. The connect screen walks you through granting read access and validating it, and connecting then scans your recent logs so you can review which providers were found.Select the bucket
Grant Vantage read access
- AWS Console
- AWS CLI
- Terraform
VantageCrossAccountRole: the name of your existing Vantage cross-account IAM role.CustomLlmEnrichmentBuckets: a comma-separated list of telemetry bucket ARNs, each asarn:aws:s3:::your-bucket/*.
s3:ListBucket and s3:GetBucketLocation. The grant above adds only object read on the telemetry bucket (s3:GetObject, and the generated policy always includes s3:GetObjectAcl).kms:Decrypt separately. See KMS-Encrypted Buckets.Check permissions and connect
YYYY/MM/DD/*.jsonl.gz layout, gzip compression, and that records match the common schema. Blocking problems (for example, objects that are not under the date layout, uncompressed .jsonl logs, or sampled records missing required fields) are shown as errors you must resolve before connecting. Nonblocking findings still let you connect: an empty bucket is shown as a notice, while sibling integrations whose sampled logs omit resource_account_id produce a warning. Then click Connect. Vantage confirms the source and immediately scans your recent gateway logs, from the first day of the previous calendar month through today, to detect which providers and provider accounts appear in the bucket. You are taken to a Scanning gateway logs page that refreshes on its own; a large bucket can take several minutes.Review detected providers and confirm
resource_account_id or Account identifiers not found: … when account IDs could not be matched to a cost integration. Logs found for unsupported providers appear in a separate banner, not the Notes column. If more than 75% of the scanned rows failed validation, a warning (“N% of scanned log rows failed validation”) suggests confirming that your objects use the common-schema YYYY/MM/DD/*.jsonl.gz format and include the required fields (provider, model, usage, and status).Choose which connected cost integrations should receive token enrichment from this bucket, then select Confirm. Vantage enriches costs for the selected integrations on each provider’s next data refresh. You can change the selection later from the source’s Manage tab.Manage Custom LLM Enrichment Sources
Manage your connected buckets from the Custom LLM Enrichment integration page. The sources table lists each bucket with its AWS account, creation date, and Status (for example, Pending before an import starts, Importing while one runs, Stable once all imports succeed, Warning if only some imports fail, Error if a scan or all imports fail, or Paused if the source is stopped). A shared-bucket warning icon appears next to the bucket name when sibling integrations requireresource_account_id; error details appear beneath the status.
Select the bucket name to open that source’s details page, which has two tabs:
- Import History, the default tab, shows every enrichment run for the source. See View Import History.
- Manage is where you choose which cost integrations receive enrichment. See Choose Which Integrations Are Enriched.
Choose Which Integrations Are Enriched
After a scan finishes, select Review on the source to choose which connected cost integrations receive enrichment (see Step 2). To change that selection later, select the bucket name and open the Manage tab. The Manage tab lists each provider integration with its import status (for example, Stable, Pending, Importing, Warning, Error, Paused, or Unenriched), and for a provider with multiple accounts shows a count like 2 of 3 accounts enabled. It lets you enable or disable enrichment per integration. Disabling an integration here stops going-forward enrichment for it but leaves its existing enriched history in place.View Import History
In the sources table, select the bucket name to open that source’s details page, which shows the Enrichment Runs table for that bucket. The Enrichment Runs table lists one row per provider cost integration and billing period that ran enrichment, newest first, with columns for the Integration (and its account), Status, Tokens Kept, Log Lines Kept, Bill Match, Billing Period, and Last Enriched At. Lifecycle changes appear as their own rows: Added when enrichment is first enabled for an integration, and Paused or Resumed when you stop, disable, resume, or re-enable it. The three percentages look similar but measure different things at different stages, so a low number in one column means something very different from a low number in another:LLM Enrichment Import History
Stop a Source
To stop a source, click the ellipses (…) next to the row and select Stop, then confirm in the Stop enrichment source dialog. This is a soft deactivation, not a hard delete: Vantage stops enriching new cost data for that bucket, but your existing enriched history is left unchanged, and the source stays visible in the list so you can bring it back at any time.Resume a Source
To resume a stopped source, select Resume in its row. Resuming restarts going-forward enrichment for the integrations that were active when you stopped the source (integrations you had already disabled individually stay disabled) and opens the Manage tab so you can adjust the selection. A stopped bucket cannot be re-added through the connect wizard; use Resume instead.View Enriched Costs on Cost Reports
Once enrichment runs, a single provider cost line is split into multiple rows, each carrying enrichment tags. You can filter and group by these tags anywhere tags are supported: Cost Reports, Virtual Tags, Budgets, and Cost Alerts. Because enrichment splits (allocates) your provider costs, enrichment tags behave like Vantage’s cost allocation tags: you can build a Virtual Tag on them, but a cost can be allocated only once, so an enrichment tag can belong to only one allocation chain.Enrichment Tag Reference
tags keys appear exactly as you emit them, with no provider prefix. The fields Vantage derives and adds itself, such as the model identifier, carry a vntg:ai: prefix (for example, vntg:ai:model); this keeps them distinct from your keys and consistent with the AI tags Vantage applies to provider costs. For example, on enriched OpenAI costs you would see vntg:ai:model with values like gpt-5.2-2025-12-11, and your own keys such as team with values like growth, not openai:model or openai:team. Because your key is just team (not provider-namespaced), the same key lines up across OpenAI, Anthropic, Azure, and the other providers, so you can group your entire AI stack by one team tag. Consistent key naming matters: team and Team are two different keys.
Enrichment tags behave like any other provider tag in the console:
- To group: open the Group By menu, select Tag, and choose the tag key, for example
vntg:ai:model, or one of your own keys such asteam. - To filter: open the Filters menu, click New Rule, select Tag, choose the Tag Key, then pick an operator and one or more values.
vntg:ai:* tags (such as vntg:ai:model); split rows also carry the tags from their usage slice. When a slice tag and an existing tag use the same key, the enrichment value wins. The leftover row (usage not covered by telemetry) keeps the provider’s existing tags and the applicable vntg:ai:* tags but carries none of the slice tags. Request identifiers (event_id, request_id, provider_request_id, flow_run_id) and resource_account_id are never turned into tags.Troubleshooting
Most errors are displayed when you click Check Permissions or Connect. The tables below list the messages you may see, their cause, and how to resolve them. Expand a section for the relevant category.Permission and access errors
Permission and access errors
Bucket and telemetry errors
Bucket and telemetry errors
My costs are not being split
My costs are not being split
- There is no active Custom LLM Enrichment source for the account, or the telemetry has not been ingested for that billing period.
- The cost row’s model or token type could not be matched to a logged request for that provider, date, and token kind.
- Records were skipped during ingestion because a required field was missing or invalid, the
providerwas blank or unsupported, themodelwas blank or could not be matched to your provider cost data, thestatuswas not successful, or nousagevalue was a positive integer.
provider to an accepted value, carry a matching model, and include at least one positive usage count.My totals changed after enabling enrichment
My totals changed after enabling enrichment
KMS-Encrypted Buckets
If the bucket you connect is encrypted with AWS Key Management Service (KMS), Check Permissions reports a decryption error until Vantage can read the objects. Either remove encryption on the bucket, or grant the cross-account rolekms:Decrypt for the encrypting key and allow that role in the KMS key policy.
The CloudFormation, CLI, and Terraform options in Step 2 grant S3 read access only, so KMS access must be added separately.
Use Cases
Each row below shows exampletags to emit on your telemetry and what that attribution enables in Vantage. The key names are examples; you choose your own, and Vantage surfaces whatever tags you send. All rows assume telemetry is delivered to a connected bucket.
Frequently Asked Questions
Which providers are supported?
Which providers are supported?
provider value. Azure support covers direct Azure integrations; Azure CSP billing accounts are not supported.For Amazon Bedrock, use the native AWS Bedrock LLM Enrichment integration instead, which reads the Model Invocation Logs AWS writes for you. Do not enable both for the same AWS account. They allocate the same Bedrock cost rows, so the same usage is counted twice in the token pool and each source’s slices receive a diluted, misleading share.What Vantage permissions do I need to enable this?
What Vantage permissions do I need to enable this?
What access does Vantage gain in my AWS account?
What access does Vantage gain in my AWS account?
s3:GetObject, s3:ListBucket, s3:GetBucketLocation, and kms:Decrypt for KMS-encrypted objects (generated policies may also include s3:GetObjectAcl). The policy attaches to your existing cross-account role; no new role is created. See Step 2: Connect the Source in Vantage.Do I need an AI gateway to use this?
Do I need an AI gateway to use this?
Will this change my totals or break existing reports?
Will this change my totals or break existing reports?
Does Vantage see my prompt content?
Does Vantage see my prompt content?
tags you choose to emit. Prompt and completion text are never collected or stored.