Skip to main content
This feature is in private preview. Contact your customer success manager to learn more about availability.
Vantage reads your own per-request LLM usage logs from an S3 bucket and joins them to your model-provider costs. Each record describes one model call: the provider, model, token counts, and the allocation 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, Segments, 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 Source integration enriches costs for Vantage’s native model-provider integrations: OpenAI, Anthropic, AWS Bedrock, Google Cloud (Vertex AI Gemini and Marketplace Claude), and Azure OpenAI. 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.
Enrichment is metadata-only. Vantage reads the provider, model, token counts, and the allocation 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. The enrichment pipeline runs through the following steps:

How Cost Rows Are Split

For each matched cost row, the cost is allocated proportionally across the tag slices present in your telemetry, weighted by token usage: attributed cost=cost row×slice tokenstotal matched tokens for row\text{attributed cost} = \text{cost row} \times \frac{\text{slice tokens}}{\text{total matched tokens for row}} Splits are additive: the sum of the enriched rows always equals the original cost row to the cent. Existing provider-level reports continue to show the same totals; enrichment only makes new dimensions available on the underlying rows.
Consider the below example: one cost row for gpt-5.2-2025-12-11 is $100 for the day, covering 100M input tokens. Your telemetry for that day groups into these tag slices:After enrichment, the single $100 row becomes three rows:The total is unchanged at $100. The leftover row carries the portion of the cost row’s tokens that your telemetry does not cover; it keeps the model tag but none of the slice tags, so totals always reconcile and no dollars are lost. Cost rows with no matching telemetry pass through without allocation splits.If your telemetry instead reports more usage than the provider billed, Vantage still allocates only the billed cost, split across your tag slices in proportion to each slice’s usage. The surplus telemetry does not create additional cost, and there is no leftover row in that case.

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 the Custom LLM Source

Setup has two steps: emit your telemetry in the common schema to S3 and connect the source in Vantage, which is also where you grant Vantage read access to the bucket.

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/DD partition.
  • Place the logs at the bucket root or under any prefix (subfolder); keep the YYYY/MM/DD date 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.
A single record looks like this:
The sections below define each part of the record: Core fields are required on every record, Usage fields carry the token counts (at least one must be a positive integer), Optional fields add context and extra allocation dimensions, Tagging guidance explains how 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.
Set provider to the identity that matches your cost integration.
Vantage normalizes model identifiers on both sides so gateway logs and provider billing join even when they differ. For example, OpenAI billing always uses dated model names (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

The usage 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. When uncached_input_tokens is omitted or null, Vantage derives it 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.
If you connect more than one integration for the same provider (for example, two OpenAI accounts) and your telemetry does not include resource_account_id, Vantage cannot tell which integration each record belongs to, and those integrations’ costs will not be enriched.

Tagging Guidance

These rules govern how your tags and top-level metadata become cost dimensions, and which values to keep out of tags.
  • Top-level service_tier, is_batch, provider_region, endpoint, and api_key_id values override fields with the same names inside tags.
  • resource_account_id must be top-level and cannot be supplied through tags.
  • Keep request_id, provider_request_id, flow_run_id, and similar request identifiers out of tags, 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.
Never include API key values, credentials, secrets, or other sensitive authentication material in any field or tag.

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, or usage) is missing, or the timestamp is blank or cannot be parsed.
  • The provider is blank or not a supported value, or the model is blank or cannot be matched to your provider cost data.
  • The status is set to anything other than success (omit it or leave it blank for successful requests).
  • No usage field contains a positive integer.

Step 2: Connect the Source in Vantage

In Vantage, go to the Integrations page and, under LLM Enrichment, add a Custom LLM Source, then select the S3 bucket that holds your telemetry. The connect screen walks you through granting read access and validating it.
You can connect one or more Custom LLM Sources (S3 buckets) per account. A connected source applies to every supported provider cost integration on the account; you select a bucket, not individual providers.
Connecting reuses your existing AWS cross-account IAM role, adding read-only access to the bucket that holds your telemetry. It does not create a new role or require new credentials.
1

Select the bucket

Select the S3 bucket that receives your telemetry.
If your bucket does not appear in the list, it may not be synced into Vantage’s inventory yet. Newly created buckets can take up to 24 hours to appear.
2

Grant Vantage read access

Deploy in the AWS account that owns the telemetry bucket, and make sure the bucket ARN in the policy matches the bucket you connect in Vantage. A mismatch is the most common cause of an access denied result when you check permissions.
The connect screen offers three ways to grant access, each prefilled for your account:
The connect screen provides a CloudFormation quick-create link that opens the AWS Console with the stack name, template URL, and parameters prefilled. Acknowledge that CloudFormation may create IAM resources, then create the stack.The stack applies the Vantage-published template with two parameters:
  • VantageCrossAccountRole: the name of your existing Vantage cross-account IAM role.
  • CustomLlmEnrichmentBuckets: a comma-separated list of telemetry bucket ARNs, each as arn:aws:s3:::your-bucket/*.
Deploy the stack in the account that owns the bucket, not necessarily your management/payer account.
Whichever method you use, Vantage needs the following read-only access to validate and ingest telemetry:Your existing Vantage cross-account role already grants 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).
The CloudFormation, CLI, and Terraform options above grant S3 read access only. If your telemetry bucket uses SSE-KMS encryption, you must grant kms:Decrypt separately. See KMS-Encrypted Buckets.
3

Check permissions and connect

Click Check Permissions. Vantage validates that it can resolve the bucket Region, list objects, and read a sample object. Then click Connect. Vantage begins joining your telemetry to your provider costs on the next data refresh for each provider.
A success message confirms the source is configured, and the bucket appears in the connected list with its AWS account and connection date. See the Troubleshooting section for any errors that are displayed.

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, Segments, 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. Allocated values show the allocated badge (calculator icon) in the console.

Enrichment Tag Reference

The keys appear exactly as you emit them, with no provider prefix. For example, on enriched OpenAI costs you would see the key 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 the 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 model (values like gpt-5.2-2025-12-11) or a tags key such as team.
  • To filter: open the Filters menu, click New Rule, select Tag, choose the Tag Key, then pick an operator and one or more values.
The tag keys appear in the Tag Key dropdown once enriched costs exist. If you use a handful of keys often, mark them as preferred tags so they sort to the top of these menus.
Enriched split rows carry the tags from their usage slice plus the model tag; they do not retain other provider tags on those split rows. The leftover row (usage not covered by telemetry) carries only the model tag. Request identifiers (event_id, request_id, provider_request_id, flow_run_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.
Confirm the permissions were deployed in the AWS account that owns the bucket, and that the bucket ARN in the policy matches the connected bucket.
Enrichment can only split costs by dimensions present in your telemetry. Costs pass through without allocation splits when any of the following is true:
  • There is no active Custom LLM 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 provider was blank or unsupported, the model was blank or could not be matched to your provider cost data, the status was not successful, or no usage value was a positive integer.
Confirm your records set provider to an accepted value, carry a matching model, and include at least one positive usage count.
Totals should not change. Splits are additive and always sum to the original cost row to the cent, and only one enrichment source can be active per account. If a total appears different, this is not expected behavior; contact Vantage Support.

KMS-Encrypted Buckets

If your telemetry bucket 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 role kms: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 example tags 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

OpenAI, Anthropic, AWS Bedrock, Google Cloud (Vertex AI Gemini and Marketplace Claude), and Azure OpenAI. You deliver one telemetry stream in the common schema, and Vantage routes each record to the matching provider’s costs based on its provider value. Azure support covers direct Azure (Azure OpenAI) integrations; Azure CSP billing accounts are not supported.
You need the Organization Owner or Integration Owner role. See Role-Based Access Control.
Read-only access to the telemetry bucket you connect: 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.
No. You emit the telemetry yourself, so this works for direct-to-provider traffic (for example, calling OpenAI or Anthropic APIs directly) as well as traffic behind a gateway. The only requirement is that you write common-schema records to S3.
No. Splits are additive and always sum to the original cost row. Existing provider-level reports continue to show the same totals; enrichment only makes new dimensions available on the underlying rows.
No. Enrichment is metadata-only. The telemetry stream carries request identifiers, the provider and model, usage counts, and the allocation tags you choose to emit. Prompt and completion text are never collected or stored.