← Agent Frameworks 🕐 16 min read
Agent Frameworks

Bedrock CUR 2.0 Column Reference — Complete Guide for AI Workload Analysis (2026)

The AWS service namespace. For native Bedrock models this is always `AmazonBedrock`. Two adjacent namespaces require explicit exclusion in Bedrock-focused queries:

See also: aws-cur-bedrock-token-finops-2026 · bedrock-finops-dashboards-2026 · ai-cost-attribution-multitenant-saas-2026

Pillar: 19 — Agent Frameworks & Observability
Scope: CUR 2.0 (AWS Data Exports) column anatomy for Amazon Bedrock inference, provisioned throughput, guardrails, and agent orchestration workloads
Research date: 2026-06-18
Contract strength: Official AWS documentation (primary); verified Athena DDL patterns (secondary)


# Column Type Default? Bedrock-specific significance
1 line_item_product_code string Yes Discriminates Bedrock vs Marketplace vs SageMaker
2 line_item_usage_type string Yes Full model identity + token direction + tier + routing in one string
3 line_item_operation string Yes Inference vs streaming vs guardrails vs agent orchestration
4 line_item_line_item_type string Yes Usage / Tax / Credit / RIFee — Bedrock never shows SP types
5 line_item_usage_amount decimal Yes Token count, not hours or requests
6 line_item_unblended_cost decimal Yes Dollar cost at list price
7 line_item_iam_principal string Opt-in Full IAM ARN of Bedrock caller — CUR 2.0 only
8 resource_tags/* map Opt-in Cost allocation tags on inference profile ARNs
9 iamPrincipal/* map Opt-in Tags on the IAM identity, not the resource
10 pricing_unit string Yes “Token” for on-demand; “ModelUnit-month” for PT
11 pricing_public_on_demand_rate decimal Yes Per-token public list rate; verify against actual unblended_cost
12 line_item_resource_id string Opt-in Model ARN or inference profile ARN
13 product_region string Yes Region where request was billed (not necessarily executed for cross-region)
14 bill_payer_account_id string Yes Management account for consolidated billing
15 line_item_usage_start_date timestamp Yes Aggregation window start; partition key for Athena performance

Section 1 — Column-by-Column Reference

1.1 line_item_product_code

Type: string
Always present: Yes

The AWS service namespace. For native Bedrock models this is always AmazonBedrock. Two adjacent namespaces require explicit exclusion in Bedrock-focused queries:

Value What it represents Exclude from Bedrock queries?
AmazonBedrock Native Bedrock on-demand inference, PT, guardrails, agents, knowledge bases This is your target
AWSMarketplace Third-party models purchased through AWS Marketplace (e.g., AI21, Cohere, Stability AI accessed via Marketplace subscription, not Bedrock native) Yes — different pricing structure, no token-level line items
AmazonSageMaker SageMaker inference endpoints, JumpStart, Autopilot Yes — completely different cost model (per-instance-hour)
AmazonBedrock + Guardrails Guardrails usage is still AmazonBedrock but distinguishable via line_item_operation No — filter by operation

Query pattern:

WHERE line_item_product_code = 'AmazonBedrock'

Gotcha: Third-party models accessed natively through Bedrock (Meta Llama, Mistral, Cohere Command R+, AI21 Jamba) all appear as AmazonBedrock, not AWSMarketplace. Marketplace-subscribed models that you then invoke via Bedrock APIs also appear as AmazonBedrock. The distinction between “Bedrock native” and “Bedrock Marketplace” emerges only in the line_item_usage_type model segment and product_from_location.


1.2 line_item_usage_type

Type: string
Always present: Yes
This is the primary key for Bedrock cost analysis.

Full anatomy of the usage type string

{REGION_CODE}-{MODEL_SEGMENT}-{TOKEN_TYPE}[-{TIER}][-cross-region-global]

Region code mapping (billing region codes, not standard AWS region IDs):

Billing code AWS region
USE1 us-east-1 (N. Virginia)
USE2 us-east-2 (Ohio)
USW2 us-west-2 (Oregon)
EUW1 eu-west-1 (Ireland)
EUC1 eu-central-1 (Frankfurt)
APS1 ap-southeast-1 (Singapore)
APN1 ap-northeast-1 (Tokyo)
CAN1 ca-central-1 (Canada)
SAE1 sa-east-1 (São Paulo)

Model segment — exactly as it appears in the usage type string (case-sensitive, no spaces):

Usage type model segment Actual model
Claude4.6Sonnet Anthropic Claude Sonnet 4.6
Claude4.6Opus Anthropic Claude Opus 4.6
Claude3.7Sonnet Anthropic Claude 3.7 Sonnet
Claude3.5Haiku Anthropic Claude 3.5 Haiku
Nova2.0Lite Amazon Nova 2 Lite
Nova2.0Micro Amazon Nova 2 Micro
Nova2.0Pro Amazon Nova 2 Pro
llama3-70b-instruct Meta Llama 3 70B Instruct
gpt-oss-120b OpenAI gpt-oss-120b (Bedrock Marketplace)
openai.gpt-oss-120b OpenAI gpt-oss-120b via mantle endpoint

Token type segment:

Suffix Meaning Relative price
-input-tokens Standard prompt tokens 1× baseline
-output-tokens Generated completion tokens ~3–5× input
-cache-read-input-token-count Prompt cache hit tokens ~0.1× input (90% discount)
-cache-write-input-token-count Prompt cache write tokens ~1.25× input (25% premium)

Tier suffix (appended after token type, before routing suffix):

Suffix Tier Pricing
(none) Standard on-demand Public list rate
-flex Flex inference (batch, lower priority) Discounted vs standard
-priority Priority inference (guaranteed capacity) Premium vs standard

Routing suffix:

Suffix Meaning
(none) In-region inference
-cross-region-global Request routed via cross-region inference profile (billed in the originating region’s billing code)
-mantle- Bedrock-mantle endpoint (used for OpenAI-compatible API surface)

Complete concrete examples:

USE1-Claude4.6Sonnet-input-tokens                           → Claude Sonnet 4.6, standard, input, in-region
USE1-Claude4.6Sonnet-output-tokens                          → Claude Sonnet 4.6, standard, output, in-region
USE1-Claude4.6Sonnet-cache-read-input-token-count           → cache read, standard
USE1-Claude4.6Sonnet-cache-write-input-token-count          → cache write, standard
USE1-Claude4.6Sonnet-output-tokens-cross-region-global      → cross-region routed, billed in USE1
USE1-Nova2.0Lite-input-tokens-flex                          → Nova 2 Lite, flex tier
USE1-gpt-oss-120b-output-tokens-priority                    → OpenAI model, priority tier
USE1-openai.gpt-oss-120b-mantle-input-tokens-standard       → OpenAI model via mantle (OAI-compat) endpoint
USE1-BedrockAgent-input-tokens                              → Agent orchestration token usage
USE1-Guardrails-text                                        → Guardrails text unit (not tokens)
USE1-Claude4.6Sonnet-ModelUnit-month                        → Provisioned throughput monthly charge

Regex to extract model from usage type (Athena/Presto):

REGEXP_EXTRACT(line_item_usage_type, '^[^-]+-(.+?)-(input|output|cache|ModelUnit|mantle)', 1)

1.3 line_item_operation

Type: string
Always present: Yes

Values observed in production as of 2026 (nomenclature stabilized January 2026 — prior to that, many Bedrock line items showed generic Usage):

Value What it covers
InvokeModelInference Synchronous InvokeModel API calls
InvokeModelStreamingInference Streaming InvokeModelWithResponseStream API calls
ConverseInference Converse API (unified conversation format)
ConverseStreamingInference Streaming Converse API
AgentInference Bedrock Agents orchestration — includes agent planner tokens
KnowledgeBaseRetrieve Bedrock Knowledge Bases retrieve-only calls
KnowledgeBaseRetrieveAndGenerate Knowledge Bases RAG combined call (includes generation tokens)
GuardrailsApplyGuardrail Standalone Guardrails invocation
ModelEvaluation Bedrock Model Evaluation job token usage
BatchInference Bedrock Batch Inference job processing
FineTuning Fine-tuning training compute (rare — also appears as separate product in some configs)

Critical: For cost governance, AgentInference tokens are typically 2–4× higher per task than direct InvokeModelInference for the same net work due to orchestration overhead (planner turns, tool-call rounds). This is not a bug — it’s the cost of autonomous orchestration.

Query pattern to compare inference modes:

WHERE line_item_product_code = 'AmazonBedrock'
  AND line_item_operation IN (
      'InvokeModelInference', 'InvokeModelStreamingInference',
      'ConverseInference', 'ConverseStreamingInference'
  )

1.4 line_item_line_item_type

Type: string
Always present: Yes

Value Meaning Appears for Bedrock?
Usage On-demand resource consumption Yes — primary type
Tax VAT/GST tax line (separate row) Yes (in applicable jurisdictions)
Credit AWS promotional or committed-spend credit applied Yes (if organization has credits)
RIFee Reserved Instance upfront or recurring fee No — Bedrock has no RI concept
SavingsPlanCoveredUsage Usage covered by Compute Savings Plan No — Bedrock Savings Plans exist but generate their own SavingsPlanCoveredUsage line type; the covered usage record shows SavingsPlanCoveredUsage
SavingsPlanNegation Negation entry offsetting list-price charge No (same reason)
DiscountedUsage Usage covered by an EC2 Reserved Instance No
Refund Credit memo Rare, possible
BundledDiscount Volume discount applied Possible at high volume
EdpDiscount Enterprise Discount Program discount Yes if org has EDP

Bedrock filter standard practice:

WHERE line_item_line_item_type = 'Usage'

Always filter to Usage unless you specifically need to analyze tax, credits, or discount lines. Failing to filter means SUM cost aggregations will double-count when credits are present.

Bedrock Savings Plans note: AWS launched Bedrock Savings Plans (1- and 3-year commitments) in late 2025. When a Savings Plan is active, the covered token usage shows as SavingsPlanCoveredUsage, not Usage. If your fleet uses Bedrock SPs, you must include both types in consumption queries:

WHERE line_item_line_item_type IN ('Usage', 'SavingsPlanCoveredUsage')

1.5 line_item_usage_amount

Type: decimal(18,8)
Always present: Yes
Unit: tokens (not hours, not requests, not API calls)

This is the most important unit distinction for Bedrock vs every other AWS service. For EC2, this column is instance-hours. For S3, it is GB-months. For Bedrock, it is token count.

Aggregation behavior: CUR aggregates usage amounts by line_item_usage_type over the export granularity window (hourly or daily). A single row in your CUR table represents potentially millions of tokens across thousands of requests that share the same usage type, account, region, and IAM principal.

Token type handling: Each of the four token types (input, output, cache-read, cache-write) appears as a separate row with its own line_item_usage_amount. You must never SUM all rows for a model — this produces a meaningless blend of token types at different unit prices.

Correct total cost calculation:

-- Right: let price × quantity handle it
SUM(line_item_unblended_cost)

-- Wrong: SUM(line_item_usage_amount) * some_rate
-- (rate varies by token type; can't apply a single rate to a blended token count)

Provisioned throughput exception: For PT model units, line_item_usage_amount is the number of ModelUnit-month fractions consumed (e.g., 0.033333 for one day of one model unit). The unit switches to ModelUnit-month as confirmed by pricing_unit.


1.6 line_item_unblended_cost

Type: decimal(18,10)
Always present: Yes

The dollar cost of the line item at the payer account’s list price, before application of Savings Plans, Reserved Instances, or credits. For Bedrock on-demand, this is:

line_item_unblended_cost = line_item_usage_amount × pricing_public_on_demand_rate

When Bedrock Savings Plans are active, line_item_unblended_cost on SavingsPlanCoveredUsage rows still shows the original unblended cost. The effective cost reduction appears in line_item_net_unblended_cost.

Related columns for net-cost analysis:

Column Meaning
line_item_unblended_cost List price (always present)
line_item_net_unblended_cost After credits, EDPs, SP discounts
line_item_blended_cost Weighted average across family (useful for consolidated billing; less useful for Bedrock)
savings_plan_savings_plan_effective_cost The effective Savings Plan cost allocated to this usage line

For most Bedrock FinOps workflows, use line_item_unblended_cost for consistency and predictability. Switch to line_item_net_unblended_cost when building CFO-facing cost reports that must reflect actual cash outflow.


1.7 line_item_iam_principal

Type: string
Availability: CUR 2.0 only — requires INCLUDE_IAM_PRINCIPAL_DATA = TRUE
Data available from: April 8, 2026

The full IAM ARN of the AWS identity that made the Bedrock API call. This is the single most powerful column for attributing Bedrock costs to teams, services, or individual developers in a multi-tenant deployment.

ARN formats

Identity type Example ARN When seen
IAM user arn:aws:iam::123456789012:user/alice Direct API key usage
IAM role (assumed, no session name) arn:aws:sts::123456789012:assumed-role/BedRockAppRole EC2/Lambda with role, no custom session name
IAM role (assumed with session name) arn:aws:sts::123456789012:assumed-role/GatewayRole/team-data-eng LiteLLM/gateway using STS AssumeRole with session name
Federated SSO user arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_PowerUser/alice@acme.com IAM Identity Center SSO
Bedrock API key arn:aws:iam::123456789012:user/BedrockAPIKey-xR2t4 Bedrock-specific API keys
Service account arn:aws:sts::123456789012:assumed-role/SageMakerExecutionRole/SageMakerPipeline SageMaker pipeline calling Bedrock

Activation

  1. Go to AWS Billing → Data Exports → select your CUR 2.0 export → Edit
  2. Under Additional content, enable IAM principal data (INCLUDE_IAM_PRINCIPAL_DATA = TRUE)
  3. Data begins populating from the activation date forward — there is no retroactive backfill
  4. Allow up to 24 hours for the first data to appear in S3 and Athena

Gateway attribution pattern

A single-role gateway (LiteLLM, Bedrock proxy, custom gateway) will show one IAM ARN for all traffic — useless for per-team chargeback. The correct pattern:

# Per-request STS assumption in LiteLLM custom auth
sts = boto3.client("sts")
response = sts.assume_role(
    RoleArn=f"arn:aws:iam::{account_id}:role/BedrockGatewayRole",
    RoleSessionName=f"team-{team_slug}",  # appears in line_item_iam_principal
    Tags=[
        {"Key": "team", "Value": team_slug},
        {"Key": "cost-center", "Value": cost_center},
        {"Key": "project", "Value": project_id},
    ],
    DurationSeconds=3600,
)
# Use response['Credentials'] for this request's Bedrock call

The RoleSessionName appears as the final segment of the ARN:

arn:aws:sts::123456789012:assumed-role/BedrockGatewayRole/team-data-eng

Session tags flow into iamPrincipal/ prefixed columns in the CUR tags map.


1.8 resource_tags/* (Cost Allocation Tags)

Type: nested within tags map column
Availability: Requires cost allocation tag activation in Billing Console
Delay: 24-hour propagation delay after tag activation; not retroactive

In CUR 2.0, cost allocation tags appear inside the tags map column with a resourceTags/ prefix. These are tags applied to AWS resources, not to IAM identities.

For Bedrock, taggable resources include:

  • Application inference profiles (have ARNs that can be tagged)
  • Custom models (fine-tuned model ARNs)
  • Provisioned throughput units

Standard Bedrock on-demand invocation has no resource ARN by default, so resourceTags/ values will be null unless you configure application inference profiles with tags and route requests through them.

Activating a tag for cost allocation:

  1. AWS Billing → Cost Allocation Tags → User-Defined Tags
  2. Activate each tag key (takes up to 24 hours; no backfill)
  3. Tag appears in CUR as resourceTags/{TagKey}

Full tag prefix taxonomy in CUR 2.0 tags column:

Prefix Source
resourceTags/ Tags on the AWS resource (inference profile ARN, custom model)
iamPrincipal/ Tags on the IAM user or role making Bedrock calls
userAttribute/ User attributes from IAM Identity Center directory
accountTag/ Tags at AWS account level (from Organizations)
costCategory/ Values derived from AWS Cost Categories rules

Athena access pattern:

-- Map accessor
tags['resourceTags/Environment']    AS environment,
tags['iamPrincipal/team']           AS team,
tags['accountTag/BusinessUnit']     AS business_unit

-- Dot operator (equivalent, CUR 2.0 only)
tags.resourceTags.Environment

1.9 iamPrincipal/* (IAM Principal Tag Columns)

Type: nested within tags map column, prefix iamPrincipal/
Availability: CUR 2.0 only; requires INCLUDE_IAM_PRINCIPAL_DATA = TRUE AND the tag key must be activated as a cost allocation tag

IAM principal tags are propagated to CUR from the tags on the IAM user or role that made the API call, and from session tags set at AssumeRole time.

Two sources of iamPrincipal/ data:

  1. IAM identity tags — tags attached directly to the IAM user or role in IAM
  2. Session tags — tags set in the AssumeRole call; these override identity tags if keys collide

Common tagging schema for Bedrock gateway attribution:

Tag key Example value Usage
team data-engineering Team-level chargeback
cost-center CC-1042 Finance chargeback code
project customer-360 Project-level attribution
environment prod Prod vs dev spend isolation
service recommendation-engine Microservice attribution
owner alice@acme.com Individual developer tracking

In Athena:

tags['iamPrincipal/team']         AS team,
tags['iamPrincipal/cost-center']  AS cost_center,
tags['iamPrincipal/project']      AS project

1.10 pricing_unit

Type: string
Always present: Yes

Value When it appears Meaning
Token On-demand inference (standard, flex, priority) Each token in line_item_usage_amount costs pricing_public_on_demand_rate dollars
ModelUnit-month Provisioned throughput One model unit purchased for a calendar month; line_item_usage_amount is the fractional month consumed
TextUnit Guardrails text processing One unit = 1,000 characters processed
ImageUnit Guardrails image processing One unit = 1 image processed
Request Some Knowledge Base retrieve-only calls Per-request pricing
GB-month Bedrock Knowledge Base storage Vector store storage

Diagnostic use: When troubleshooting unexpected cost spikes, check pricing_unit first. A spike in ModelUnit-month charges means PT units are running idle; a spike in TextUnit charges means Guardrails throughput has grown unexpectedly.


1.11 pricing_public_on_demand_rate

Type: decimal(18,10)
Always present: Yes

The AWS public list rate for one unit of the pricing_unit. For Bedrock on-demand token inference, this is dollars per token.

Example values (illustrative — verify against current Bedrock pricing page):

Usage type Approximate rate (USD/token)
*-Claude4.6Sonnet-input-tokens $0.000003 ($3.00/MTok)
*-Claude4.6Sonnet-output-tokens $0.000015 ($15.00/MTok)
*-Claude4.6Sonnet-cache-read-input-token-count $0.0000003 ($0.30/MTok)
*-Claude4.6Sonnet-cache-write-input-token-count $0.00000375 ($3.75/MTok)
*-Claude4.6Opus-input-tokens $0.000015 ($15.00/MTok)
*-Claude4.6Opus-output-tokens $0.000075 ($75.00/MTok)

Warning: pricing_public_on_demand_rate reflects the public rack rate. If your organization has EDP, volume discounts, or Bedrock Savings Plans, the effective rate differs. Use line_item_unblended_cost / line_item_usage_amount to compute the actual effective rate per token for each line item.

Unit conversion note: CUR reports rates in dollars-per-single-token. To get the familiar “per million tokens” figure:

pricing_public_on_demand_rate * 1000000 AS rate_per_million_tokens

1.12 line_item_resource_id

Type: string
Availability: Requires INCLUDE_RESOURCES = TRUE in Data Export configuration
Delay: No additional delay beyond standard CUR propagation

For Bedrock, line_item_resource_id is populated only when the request was made through an application inference profile or a custom model (fine-tuned or imported). Direct invocation of foundation model IDs does not produce a resource ID.

ARN patterns:

Resource type ARN pattern
Application inference profile arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/AIProfName
Custom model arn:aws:bedrock:us-east-1:123456789012:custom-model/CustomModelId
Provisioned throughput arn:aws:bedrock:us-east-1:123456789012:provisioned-model/PtModelId
Cross-region inference profile arn:aws:bedrock:us-east-1::foundation-model/us.anthropic.claude-sonnet-4-5-20251001-v1:0 (system-defined; no account segment)
Direct foundation model invocation (null — no resource ARN)

Practical implication: To get resource-level tag attribution (via resourceTags/ tag prefix), you must route traffic through application inference profiles with tags applied. This is the only way to attach resource tags to Bedrock on-demand inference. If all your traffic hits foundation models directly, this column will be null and resourceTags/ values will be empty.


1.13 product_region vs line_item_availability_zone

Type: string (both)
Always present: Yes

Column What it contains For Bedrock
product_region The AWS region where the service is configured or billed The region code of the AWS region in which the billing account created the Bedrock usage (may differ from execution region for cross-region inference)
line_item_availability_zone The specific AZ for zonal services Always empty for Bedrock — Bedrock is a regional service with no AZ-level billing

Cross-region inference note: When cross-region inference is active, the originating region’s billing code appears in line_item_usage_type (e.g., USE1-...), and product_region reflects the originating region (us-east-1). The actual compute may run in us-west-2 or other regions — CUR does not expose the execution region. Use Bedrock invocation logs for execution-region visibility.

product_from_location vs product_region:

Column Example
product_region us-east-1
product_from_location US East (N. Virginia)

Both represent the same region. product_from_location is human-readable; use product_region for programmatic filtering.


1.14 bill_payer_account_id vs line_item_usage_account_id

Type: string (both)
Always present: Yes

Column Contains Use case
bill_payer_account_id AWS account ID of the management (payer) account Organizational rollup; identifying which org the usage belongs to
line_item_usage_account_id AWS account ID where the Bedrock API call was made Per-account cost allocation; multi-account fleet analysis
bill_payer_account_name Human-readable name of management account CUR 2.0 only — not available in legacy CUR
line_item_usage_account_name Human-readable name of the member account CUR 2.0 only — not available in legacy CUR

Multi-account pattern: In an AWS Organization, the CUR is exported from the management account and contains usage from all member accounts. Filter to a specific team’s account:

WHERE line_item_usage_account_id = '123456789012'

For consolidated cross-account rollup:

GROUP BY bill_payer_account_id, line_item_usage_account_id, line_item_usage_account_name

The combination of line_item_usage_account_id + line_item_iam_principal is the two-level attribution hierarchy: account → identity.


1.15 line_item_usage_start_date / line_item_usage_end_date

Type: timestamp
Always present: Yes
These are the Athena partition keys — always filter on them.

CUR 2.0 supports three granularities configured at export creation time:

Granularity usage_startusage_end Best for
HOURLY 1-hour windows Real-time alerting, anomaly detection
DAILY 24-hour windows Standard cost reporting, dashboards
MONTHLY Calendar month Invoice reconciliation, executive reports

Bedrock-specific granularity note: Bedrock does not report token usage in real time. There is typically a 4–8 hour lag between when a Bedrock API call is made and when the corresponding token usage appears in a HOURLY CUR export. For near-real-time attribution (sub-hour), use Bedrock invocation logs, not CUR.

Partition projection (Athena): Always include a date filter to avoid full-table scans:

WHERE line_item_usage_start_date >= DATE_ADD('day', -30, CURRENT_DATE)
  AND line_item_usage_start_date < CURRENT_DATE

Section 2 — Columns That Don’t Apply to Bedrock

These columns are present in the CUR 2.0 schema (125 fixed columns) but will always be null or empty for Bedrock line items. Knowing this prevents confusing nulls during data exploration.

Column group Columns Why null for Bedrock
Reserved Instance reservation_reservation_arn, reservation_effective_cost, reservation_amortized_upfront_fee_for_billing_period, reservation_unused_quantity, reservation_unused_recurring_fee Bedrock has no RI purchasing model
Savings Plan savings_plan_savings_plan_arn, savings_plan_offering_type, savings_plan_payment_option, savings_plan_purchase_term Bedrock Savings Plans (launched 2025) use a different column: savings_plan_savings_plan_effective_cost; the RI-style SP columns remain null
EC2 Instance product_instance_type, product_instance_family, product_vcpu, product_memory, product_tenancy, product_operating_system Bedrock is serverless; no instance selection
Availability Zone line_item_availability_zone Bedrock is regional, not zonal
Network product_transfer_type, product_from_region_code, product_to_region_code Data transfer is billed as a separate AmazonEC2 line item (egress), not within the Bedrock line item
EBS/Storage product_volume_type, product_storage_media N/A
Spot product_spot_price Bedrock has no Spot equivalent (Flex inference is the analogous concept but billed differently)

Section 3 — CUR 2.0 Opt-In Columns: Activation Requirements

3.1 line_item_iam_principal — IAM Principal Attribution

Activation: AWS Billing Console → Data Exports → Edit export → Additional content → IAM principal data
CLI equivalent:

aws bcm-data-exports update-export \
  --export-arn "arn:aws:bcm-data-exports:us-east-1:123456789012:export/your-export-id" \
  --export '{
    "DataQuery": {
      "QueryStatement": "SELECT * FROM COST_AND_USAGE_REPORT",
      "TableConfigurations": {
        "COST_AND_USAGE_REPORT": {
          "INCLUDE_IAM_PRINCIPAL_DATA": "TRUE",
          "TIME_GRANULARITY": "DAILY",
          "INCLUDE_RESOURCES": "TRUE",
          "INCLUDE_SPLIT_COST_ALLOCATION_DATA": "FALSE"
        }
      }
    }
  }'

Key constraints:

  • Data begins from activation date — no retroactive backfill
  • If activated today, data from before today will have null line_item_iam_principal
  • 24-hour propagation delay for data to appear in Athena
  • Requires the CUR 2.0 export, not legacy CUR

3.2 Resource Tags (INCLUDE_RESOURCES = TRUE + tag activation)

Two-step process:

  1. Enable INCLUDE_RESOURCES = TRUE in the export configuration (populates line_item_resource_id)
  2. Activate each tag key in AWS Billing → Cost Allocation Tags (populates resourceTags/ columns)

Activation timeline: After activating a tag key, wait 24 hours before the tag appears in CUR data. Historical data before activation date will not have tag values.

Not retroactive: If you activate resourceTags/team on June 18, data from June 17 and earlier shows null for that tag even if the resource was tagged for months.

3.3 Split Cost Allocation Data (INCLUDE_SPLIT_COST_ALLOCATION_DATA)

Splits shared resource costs (e.g., an EKS cluster) across consumer namespaces. For Bedrock, this feature has limited applicability because Bedrock is already attributed per API call via IAM principal. However, if you run Bedrock via a shared SageMaker endpoint, split cost allocation can apportion the endpoint cost by traffic ratio.

Not recommended to enable for pure Bedrock workloads — adds schema complexity without benefit.


Section 4 — Athena DDL with Partition Projection

CREATE EXTERNAL TABLE IF NOT EXISTS bedrock_cur (
    -- Bill
    bill_invoice_id                         STRING,
    bill_billing_entity                     STRING,
    bill_bill_type                          STRING,
    bill_payer_account_id                   STRING,
    bill_payer_account_name                 STRING,
    bill_billing_period_start_date          TIMESTAMP,
    bill_billing_period_end_date            TIMESTAMP,

    -- Line item (core)
    line_item_usage_account_id              STRING,
    line_item_usage_account_name            STRING,
    line_item_line_item_type                STRING,
    line_item_usage_start_date              TIMESTAMP,
    line_item_usage_end_date                TIMESTAMP,
    line_item_product_code                  STRING,
    line_item_usage_type                    STRING,
    line_item_operation                     STRING,
    line_item_availability_zone             STRING,
    line_item_resource_id                   STRING,
    line_item_usage_amount                  DOUBLE,
    line_item_normalization_factor          DOUBLE,
    line_item_normalized_usage_amount       DOUBLE,
    line_item_currency_code                 STRING,
    line_item_unblended_rate                STRING,
    line_item_unblended_cost                DOUBLE,
    line_item_blended_rate                  STRING,
    line_item_blended_cost                  DOUBLE,
    line_item_net_unblended_rate            STRING,
    line_item_net_unblended_cost            DOUBLE,
    line_item_iam_principal                 STRING,    -- CUR 2.0 opt-in

    -- Product
    product_servicecode                     STRING,
    product_region                          STRING,
    product_from_location                   STRING,
    product_from_location_type              STRING,
    product_product_name                    STRING,

    -- Pricing
    pricing_rate_id                         STRING,
    pricing_public_on_demand_cost           DOUBLE,
    pricing_public_on_demand_rate           STRING,
    pricing_term                            STRING,
    pricing_unit                            STRING,

    -- Savings Plan (present but null for standard Bedrock)
    savings_plan_savings_plan_arn           STRING,
    savings_plan_savings_plan_rate          STRING,
    savings_plan_used_commitment            DOUBLE,
    savings_plan_total_commitment_to_date   DOUBLE,
    savings_plan_savings_plan_effective_cost DOUBLE,
    savings_plan_amortized_upfront_commitment_for_billing_period DOUBLE,
    savings_plan_recurring_commitment_for_billing_period DOUBLE,
    savings_plan_offering_type              STRING,
    savings_plan_payment_option             STRING,
    savings_plan_purchase_term              STRING,
    savings_plan_start_time                 STRING,
    savings_plan_end_time                   STRING,

    -- Reservation (always null for Bedrock)
    reservation_reservation_arn             STRING,
    reservation_effective_cost              DOUBLE,

    -- Tags (map — includes resourceTags/, iamPrincipal/, accountTag/, costCategory/)
    tags                                    MAP<STRING, STRING>
)
PARTITIONED BY (
    -- Partition on year/month for Athena partition projection
    year  STRING,
    month STRING
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION 's3://your-cur-bucket/your-export-prefix/your-export-name/'
TBLPROPERTIES (
    -- Partition projection: eliminates need for MSCK REPAIR TABLE
    'projection.enabled'          = 'true',
    'projection.year.type'        = 'integer',
    'projection.year.range'       = '2024,2030',
    'projection.year.digits'      = '4',
    'projection.month.type'       = 'integer',
    'projection.month.range'      = '1,12',
    'projection.month.digits'     = '2',
    'storage.location.template'   = 's3://your-cur-bucket/your-export-prefix/your-export-name/year=${year}/month=${month}/',
    'classification'              = 'parquet',
    'parquet.compression'         = 'SNAPPY'
);

Notes on the DDL:

  • Replace your-cur-bucket, your-export-prefix, your-export-name with your actual values
  • The S3 path format above matches CUR 2.0’s default folder structure from Data Exports
  • projection.enabled = true means new monthly data is automatically queryable without MSCK REPAIR TABLE
  • CUR 2.0 exports to Parquet by default; Parquet is strongly preferred over CSV for Athena performance
  • For daily-granularity exports, the partition structure is year=${year}/month=${month}/ — same structure; the files inside cover individual days

Bedrock-specific view (recommended for daily use):

CREATE OR REPLACE VIEW bedrock_usage AS
SELECT
    line_item_usage_start_date,
    line_item_usage_end_date,
    bill_payer_account_id,
    line_item_usage_account_id,
    line_item_usage_account_name,
    line_item_product_code,
    line_item_usage_type,
    line_item_operation,
    line_item_line_item_type,
    line_item_usage_amount,
    line_item_unblended_cost,
    line_item_net_unblended_cost,
    line_item_resource_id,
    line_item_iam_principal,
    pricing_unit,
    pricing_public_on_demand_rate,
    product_region,
    tags,
    -- Extracted fields for convenience
    REGEXP_EXTRACT(line_item_usage_type, '^([^-]+)-', 1)                                          AS billing_region_code,
    REGEXP_EXTRACT(line_item_usage_type, '^[^-]+-(.+?)-(input|output|cache|ModelUnit|mantle)', 1) AS model_name,
    CASE
        WHEN line_item_usage_type LIKE '%-input-tokens%'           THEN 'input'
        WHEN line_item_usage_type LIKE '%-output-tokens%'          THEN 'output'
        WHEN line_item_usage_type LIKE '%-cache-read-input-token%' THEN 'cache_read'
        WHEN line_item_usage_type LIKE '%-cache-write-input-token%'THEN 'cache_write'
        WHEN line_item_usage_type LIKE '%-ModelUnit%'              THEN 'provisioned_throughput'
        WHEN line_item_usage_type LIKE '%-TextUnit%'               THEN 'guardrails_text'
        ELSE 'other'
    END                                                                                            AS token_type,
    CASE
        WHEN line_item_usage_type LIKE '%-flex%'     THEN 'flex'
        WHEN line_item_usage_type LIKE '%-priority%' THEN 'priority'
        WHEN line_item_usage_type LIKE '%-ModelUnit%'THEN 'provisioned'
        ELSE 'standard'
    END                                                                                            AS inference_tier,
    line_item_usage_type LIKE '%-cross-region-global%'                                            AS is_cross_region,
    tags['iamPrincipal/team']                                                                     AS iam_team,
    tags['iamPrincipal/cost-center']                                                              AS iam_cost_center,
    tags['iamPrincipal/project']                                                                  AS iam_project,
    tags['resourceTags/Environment']                                                              AS resource_env
FROM bedrock_cur
WHERE line_item_product_code = 'AmazonBedrock'
  AND line_item_line_item_type IN ('Usage', 'SavingsPlanCoveredUsage');

Section 5 — Five Production-Grade Athena Queries

All queries assume the bedrock_usage view above is in place and use your_cur_database as the Glue database name.

Query 1: Complete cost breakdown by model + token direction + tier + account

-- Full attribution matrix: who spent what on which model and token type
-- Recommended: run daily, output to QuickSight or Grafana

SELECT
    DATE_TRUNC('day', line_item_usage_start_date)  AS usage_date,
    line_item_usage_account_id,
    line_item_usage_account_name,
    product_region                                  AS aws_region,
    model_name,
    token_type,
    inference_tier,
    is_cross_region,
    line_item_operation,
    COUNT(DISTINCT line_item_usage_type)            AS distinct_usage_types,
    SUM(line_item_usage_amount)                     AS total_tokens,
    SUM(line_item_unblended_cost)                   AS total_cost_usd,
    SUM(line_item_net_unblended_cost)               AS net_cost_usd,
    -- Effective rate per million tokens
    SUM(line_item_unblended_cost)
        / NULLIF(SUM(line_item_usage_amount), 0)
        * 1000000                                   AS effective_rate_per_mtok
FROM your_cur_database.bedrock_usage
WHERE line_item_usage_start_date >= DATE_ADD('day', -30, CURRENT_DATE)
  AND line_item_usage_start_date < CURRENT_DATE
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9
ORDER BY usage_date DESC, total_cost_usd DESC;

Query 2: IAM principal attribution with team tag extraction

-- Per-identity cost attribution; requires INCLUDE_IAM_PRINCIPAL_DATA = TRUE
-- session_name extracts the human-readable part from assumed-role ARNs

SELECT
    DATE_TRUNC('day', line_item_usage_start_date)  AS usage_date,
    line_item_usage_account_id,
    line_item_iam_principal,
    -- For assumed-role ARNs, extract session name (team slug from gateway AssumeRole)
    REGEXP_EXTRACT(line_item_iam_principal,
        'assumed-role/[^/]+/(.+)$', 1)              AS session_name,
    -- IAM principal tags (session tags from gateway, or tags on the IAM role)
    iam_team,
    iam_cost_center,
    iam_project,
    model_name,
    token_type,
    SUM(line_item_usage_amount)                     AS total_tokens,
    SUM(line_item_unblended_cost)                   AS total_cost_usd
FROM your_cur_database.bedrock_usage
WHERE line_item_usage_start_date >= DATE_ADD('day', -30, CURRENT_DATE)
  AND line_item_usage_start_date < CURRENT_DATE
  AND line_item_iam_principal IS NOT NULL
GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9
ORDER BY usage_date DESC, total_cost_usd DESC;

Query 3: Cache efficiency ratio — cache reads vs total input tokens

-- Cache efficiency: what fraction of input tokens are served from cache?
-- High cache hit rate → lower effective cost per input token
-- Formula: cache_read_tokens / (standard_input_tokens + cache_read_tokens + cache_write_tokens)

WITH daily_token_breakdown AS (
    SELECT
        DATE_TRUNC('day', line_item_usage_start_date) AS usage_date,
        line_item_usage_account_id,
        model_name,
        iam_team,
        SUM(CASE WHEN token_type = 'input'       THEN line_item_usage_amount ELSE 0 END) AS input_tokens,
        SUM(CASE WHEN token_type = 'output'      THEN line_item_usage_amount ELSE 0 END) AS output_tokens,
        SUM(CASE WHEN token_type = 'cache_read'  THEN line_item_usage_amount ELSE 0 END) AS cache_read_tokens,
        SUM(CASE WHEN token_type = 'cache_write' THEN line_item_usage_amount ELSE 0 END) AS cache_write_tokens,
        SUM(CASE WHEN token_type = 'input'       THEN line_item_unblended_cost ELSE 0 END) AS input_cost,
        SUM(CASE WHEN token_type = 'output'      THEN line_item_unblended_cost ELSE 0 END) AS output_cost,
        SUM(CASE WHEN token_type = 'cache_read'  THEN line_item_unblended_cost ELSE 0 END) AS cache_read_cost,
        SUM(CASE WHEN token_type = 'cache_write' THEN line_item_unblended_cost ELSE 0 END) AS cache_write_cost,
        SUM(line_item_unblended_cost)                                                       AS total_cost
    FROM your_cur_database.bedrock_usage
    WHERE line_item_usage_start_date >= DATE_ADD('day', -30, CURRENT_DATE)
      AND line_item_usage_start_date < CURRENT_DATE
      AND token_type IN ('input', 'output', 'cache_read', 'cache_write')
    GROUP BY 1, 2, 3, 4
)
SELECT
    usage_date,
    line_item_usage_account_id,
    model_name,
    iam_team,
    input_tokens,
    output_tokens,
    cache_read_tokens,
    cache_write_tokens,
    -- Cache hit ratio: cache reads / all input-side tokens
    ROUND(
        cache_read_tokens * 100.0
        / NULLIF(input_tokens + cache_read_tokens + cache_write_tokens, 0),
        2
    )                                                                   AS cache_hit_pct,
    total_cost                                                          AS total_cost_usd,
    -- What would cost be with no cache at all (all reads billed at input rate)?
    -- Requires knowing the input rate; this uses the ratio from actuals
    (cache_read_cost / NULLIF(cache_read_tokens, 0))
        * (input_tokens + cache_read_tokens + cache_write_tokens)
        + output_cost                                                   AS cost_without_cache_usd,
    total_cost - (
        (cache_read_cost / NULLIF(cache_read_tokens, 0))
            * (input_tokens + cache_read_tokens + cache_write_tokens)
            + output_cost
    )                                                                   AS cache_savings_usd
FROM daily_token_breakdown
ORDER BY usage_date DESC, total_cost DESC;

Query 4: PT idle cost detection — ModelUnit charges with low token throughput

-- Provisioned throughput idle detection
-- ModelUnit-month charges are fixed regardless of utilization
-- Join PT costs against actual inference token volume on the same model

WITH pt_charges AS (
    SELECT
        DATE_TRUNC('month', line_item_usage_start_date)   AS billing_month,
        line_item_usage_account_id,
        model_name,
        line_item_resource_id                              AS pt_arn,
        SUM(line_item_usage_amount)                        AS model_units_consumed,
        SUM(line_item_unblended_cost)                      AS pt_cost_usd
    FROM your_cur_database.bedrock_usage
    WHERE token_type = 'provisioned_throughput'
      AND line_item_usage_start_date >= DATE_ADD('day', -90, CURRENT_DATE)
    GROUP BY 1, 2, 3, 4
),
inference_tokens AS (
    SELECT
        DATE_TRUNC('month', line_item_usage_start_date)   AS billing_month,
        line_item_usage_account_id,
        model_name,
        SUM(CASE WHEN token_type = 'input'  THEN line_item_usage_amount ELSE 0 END) AS input_tokens,
        SUM(CASE WHEN token_type = 'output' THEN line_item_usage_amount ELSE 0 END) AS output_tokens,
        SUM(line_item_unblended_cost)                                                AS inference_cost_usd
    FROM your_cur_database.bedrock_usage
    WHERE token_type IN ('input', 'output')
      AND inference_tier = 'provisioned'
      AND line_item_usage_start_date >= DATE_ADD('day', -90, CURRENT_DATE)
    GROUP BY 1, 2, 3
)
SELECT
    p.billing_month,
    p.line_item_usage_account_id,
    p.model_name,
    p.pt_arn,
    p.model_units_consumed,
    p.pt_cost_usd,
    COALESCE(i.input_tokens, 0)                            AS input_tokens,
    COALESCE(i.output_tokens, 0)                           AS output_tokens,
    COALESCE(i.inference_cost_usd, 0)                      AS inference_cost_usd,
    p.pt_cost_usd + COALESCE(i.inference_cost_usd, 0)      AS total_pt_spend_usd,
    -- Utilization signal: tokens generated per model-unit-month; low = idle
    COALESCE(i.input_tokens + i.output_tokens, 0)
        / NULLIF(p.model_units_consumed, 0)                AS tokens_per_model_unit,
    -- Flag idle: token throughput below 10M tokens per model-unit-month suggests underutilization
    CASE WHEN COALESCE(i.input_tokens + i.output_tokens, 0)
                / NULLIF(p.model_units_consumed, 0) < 10000000
         THEN TRUE ELSE FALSE
    END                                                    AS likely_idle
FROM pt_charges p
LEFT JOIN inference_tokens i
    ON p.billing_month = i.billing_month
    AND p.line_item_usage_account_id = i.line_item_usage_account_id
    AND p.model_name = i.model_name
ORDER BY p.billing_month DESC, p.pt_cost_usd DESC;

Query 5: Cross-account consolidated billing rollup

-- Org-wide Bedrock spend rollup for management account CUR
-- Groups by payer → member account → model family → token type
-- Use for monthly CFO reporting across business units

WITH monthly_by_account AS (
    SELECT
        DATE_TRUNC('month', line_item_usage_start_date)   AS billing_month,
        bill_payer_account_id,
        line_item_usage_account_id,
        line_item_usage_account_name,
        -- Model family grouping from model_name segment
        CASE
            WHEN model_name LIKE '%Claude%'  THEN 'Anthropic Claude'
            WHEN model_name LIKE '%Nova%'    THEN 'Amazon Nova'
            WHEN model_name LIKE '%Titan%'   THEN 'Amazon Titan'
            WHEN model_name LIKE '%llama%'   THEN 'Meta Llama'
            WHEN model_name LIKE '%mistral%' THEN 'Mistral'
            WHEN model_name LIKE '%cohere%'  THEN 'Cohere'
            WHEN model_name LIKE '%gpt%'     THEN 'OpenAI (Bedrock Marketplace)'
            ELSE 'Other'
        END                                                AS model_family,
        token_type,
        inference_tier,
        is_cross_region,
        SUM(line_item_usage_amount)                        AS total_tokens,
        SUM(line_item_unblended_cost)                      AS total_cost_usd,
        SUM(line_item_net_unblended_cost)                  AS net_cost_usd
    FROM your_cur_database.bedrock_usage
    WHERE line_item_usage_start_date >= DATE_ADD('month', -3, DATE_TRUNC('month', CURRENT_DATE))
      AND line_item_usage_start_date < DATE_TRUNC('month', CURRENT_DATE)
    GROUP BY 1, 2, 3, 4, 5, 6, 7, 8
)
SELECT
    billing_month,
    bill_payer_account_id,
    line_item_usage_account_id,
    line_item_usage_account_name,
    model_family,
    token_type,
    inference_tier,
    is_cross_region,
    total_tokens,
    total_cost_usd,
    net_cost_usd,
    -- Month-over-month cost change (self-join via window function)
    total_cost_usd - LAG(total_cost_usd) OVER (
        PARTITION BY line_item_usage_account_id, model_family, token_type, inference_tier
        ORDER BY billing_month
    )                                                      AS mom_cost_delta_usd,
    -- Share of this account's total Bedrock spend
    total_cost_usd * 100.0 / NULLIF(SUM(total_cost_usd) OVER (
        PARTITION BY billing_month, bill_payer_account_id
    ), 0)                                                  AS pct_of_org_bedrock_spend
FROM monthly_by_account
ORDER BY billing_month DESC, total_cost_usd DESC;

Section 6 — CUR 2.0 vs CUR Legacy Differences for Bedrock

Capability Legacy CUR 1.0 CUR 2.0 (Data Exports)
Bedrock token-type line items Yes Yes
line_item_usage_type model+token anatomy Yes Yes
line_item_operation = InvokeModelInference Yes (from Jan 2026) Yes (from Jan 2026)
line_item_iam_principal column No Yes (opt-in, data from Apr 8, 2026)
iamPrincipal/ tag prefix in tags map No Yes (opt-in)
tags as structured map column No (flat resource_tags_* columns) Yes (single tags MAP<STRING,STRING>)
Fixed schema (no monthly column drift) No — schema can change each month Yes — 125 fixed columns, stable
bill_payer_account_name No Yes
line_item_usage_account_name No Yes
product_* column naming Flat: product_servicecode, product_region Map-style: product['servicecode'] OR dot: product.servicecode (flat still works)
Athena table name Varies by export name configuration COST_AND_USAGE_REPORT (default)
Configurable granularity Hourly or daily HOURLY, DAILY, or MONTHLY
Parquet export Available Default (preferred)
Delivery lag 24h for daily files 24h for daily files (same)
Bedrock Savings Plan SavingsPlanCoveredUsage rows Yes Yes
Cross-region inference *-cross-region-global suffix Yes Yes
Session tags on IAM roles surfaced to CUR No Yes via iamPrincipal/ prefix (opt-in)
userAttribute/ prefix (IAM Identity Center attributes) No Yes (CUR 2.0 only)

Migration path from legacy CUR: The most significant breaking change when migrating from legacy CUR to CUR 2.0 is the product_* column naming convention. Legacy CUR has flat columns like product_product_name, product_servicecode. CUR 2.0 supports both the dot accessor (product.servicecode) and the bracket map accessor (product['servicecode']), but the legacy flat column names do not exist in CUR 2.0. Any existing Athena queries using product_product_name must be updated to product['product_name'] or the equivalent dot form.

The second migration change is the tags column. Legacy CUR creates individual columns named resource_tags_user_Environment, resource_tags_user_Team, etc. — one column per activated tag key. CUR 2.0 consolidates all tags into a single MAP<STRING,STRING> column accessed as tags['resourceTags/Environment']. Queries that filter on legacy flat tag columns must be rewritten.


Quick-Reference Cheat Sheet

PRODUCT CODE        AmazonBedrock (not AWSMarketplace, not AmazonSageMaker)
LINE ITEM TYPE      Usage  (add SavingsPlanCoveredUsage if org uses Bedrock SPs)
USAGE AMOUNT UNIT   tokens (not hours, not requests)
USAGE TYPE FORMAT   {REGION}-{MODEL}-{TOKEN_TYPE}[-TIER][-cross-region-global]
TOKEN TYPES         input / output / cache_read / cache_write / provisioned_throughput
PRICING UNIT        Token (on-demand) | ModelUnit-month (PT) | TextUnit (guardrails)
IAM PRINCIPAL       CUR 2.0 opt-in only | data from Apr 8, 2026 | no retroactive fill
RESOURCE TAGS       Activate in Billing Console | 24h delay | not retroactive
PARTITION KEY       line_item_usage_start_date — always filter this column in Athena
GRANULARITY LAG     4–8h delay from API call to CUR row; use invocation logs for sub-hour
NULL COLUMNS        RI columns, SP columns (except savings_plan_effective_cost), EC2 instance, AZ