Skip to content

Why don't AWS invoice service charges match AWS Cost Explorer or AWS Cost and Usage Report charges?

8 minute read
Content level: Intermediate
2

Ever noticed that your AWS invoice charges don't match what you see in AWS Cost Explorer or the AWS Cost and Usage Report (CUR)? You're not alone. This happens because Data Transfer charges appear separately on your invoice but are bundled with their originating service in Cost Explorer and CUR. This guide walks you through the filtering and aggregation steps needed to reconcile charges across all your billing tools.

When you try to reconcile charges between your AWS invoice and AWS Cost Explorer or the AWS Cost and Usage Report (CUR) as part of your compliance processes, you might find that certain service charges don't match. You might first notice this with Amazon Elastic Compute Cloud (Amazon EC2), but discrepancies can also occur with Amazon Relational Database Service (Amazon RDS), Amazon Simple Storage Service (Amazon S3), and other services.

TL;DR: This happens because Data Transfer charges are reported as a separate service line item on the Bills page of the AWS Billing and Cost Management console. In Cost Explorer and CUR, those same charges are reported under the service that generated them.

To reconcile your invoice with Cost Explorer or CUR, aggregate costs by Unblended costs, filter in the desired service charges, and filter out Data Transfer charges for those services.

Read on for a detailed explanation and step-by-step instructions.


How charges appear on your invoice

Service charges on your invoice are split into multiple charge types that can vary according to your purchase options and commercial agreements.

Screenshot of the AWS Bills page showing service charges split by charge type, including Charges, Credits, and Tax line items

Typically, both the total cost (excluding tax) and the Charges line item (which corresponds to on-demand usage) don't match the charges in Cost Explorer or CUR. However, the other charge types do match when you filter or group them separately. This discrepancy occurs because the service charges exclude Data Transfer charges, which are reported in their own section as a separate service.

Amazon EC2 is a particularly notable example because it typically involves multiple purchase options. In Cost Explorer, Amazon EC2 is split into two services: EC2-Instances (running hours and EC2 Data Transfer Out charges) and EC2 - Other (all other EC2 Data Transfer charges and supporting services, such as Amazon Elastic Block Store (Amazon EBS) and NAT gateways, among others). In CUR, this separation doesn't exist — all EC2 charges, including Data Transfer, Amazon EBS, and related charges, are reported with line_item_product_code = 'AmazonEC2'.

The Knowing the differences between Billing and Cost Explorer data documentation describes this behavior:

For example, let's say that you want to understand compute costs for Amazon Elastic Compute Cloud compared to ancillary cost, such as Amazon Elastic Block Store volumes or NAT gateways. Instead of a single group for Amazon EC2 costs, Cost Explorer will group costs into EC2 - Instances and EC2 - Other.

In another example, to help analyze data transfer costs, Cost Explorer groups your transfer costs by service. In billing data, data transfer costs are grouped into a single service named Data Transfer.

The following sections show how to apply the correct filters in Cost Explorer and CUR to reconcile your charges.

Cost Explorer

Amazon EC2

To match Amazon EC2 charges in AWS Cost Explorer, follow these steps:

  1. In Advanced options (near the bottom of the rightmost column), set Aggregate costs by to Unblended Costs.
  2. Set Dimension to Charge Type.
  3. Apply the following filters:
    • Service — include EC2 - Other and EC2-Instances.
    • Usage Type Group — exclude all groups that start with EC2: Data Transfer.
    • Usage Type — exclude all types that contain VpcPeering.

Once filtered, sum these values to match your invoice costs:

  • Service Total Cost — Sum the Cost Explorer Total Costs with the invoice Tax line item. Tax in Cost Explorer is reported as a separate service, so it's excluded from the filters above.
  • Service Charges — Sum all non-negative Cost Explorer values, such as Usage, Savings Plans Covered Usage, and Recurring Reservation Fee.
  • Other invoiced charges — These should match their equivalent charge type in Cost Explorer (for example, Credits, RI Volume Discount, or Cross-Service Discount).

Note: If you have a Savings Plans Private Pricing Agreement (PPA), your Cost Explorer Savings Plan Covered Usage and Private Pricing Agreement values will not match the invoice values.

This is due to how the PPA is applied to Savings Plans — fees are always reported as net costs, even if you don't select Net Amortized or Net Unblended in Cost Explorer. PPA savings for Savings Plans are not reported separately from the fees in Cost Explorer, whereas on the invoice they are. As a result, the Cost Explorer Covered Usage will be larger than the invoice amount, while the PPA Discount will be smaller.

CUR

This section provides Amazon Athena queries for both CUR 2.0 and CUR Legacy formats. If you're setting up a new report, AWS recommends using CUR 2.0.

These queries assume you have a Cross-Service Discount Private Pricing Agreement (previously known as Enterprise Discount Program, or EDP) with AWS. If you don't, adjust the queries by removing the lines that reference EDP discounts, as noted in the SQL comments.

Prerequisites: You need Amazon Athena configured with your CUR data. Replace all <PLACEHOLDER> values in the queries below with your own account details.

CUR 2.0

Run this query in Amazon Athena. Replace the placeholders and adjust the billing_period to the invoice month you want to reconcile. For details on CUR 2.0 column names, see the CUR 2.0 data dictionary.

with filtered_data as (
    select
        line_item_line_item_type,
        line_item_unblended_cost,
        -- If you don't have an EDP, delete the line below and the comma above
        discount['edp_discount'] as edp_discount
    from <CUR_TABLE>
    where
        -- Adjust to the invoice month (format: YYYY-MM)
        billing_period = '<YYYY-MM>'
        -- Adjust to the desired service
        and line_item_product_code = 'AmazonEC2'
        -- Adjust to your payer account ID
        and bill_payer_account_id = '<PAYER_ACCOUNT_ID>'
        and line_item_line_item_type not in ('DiscountedUsage', 'EdpDiscount')
        and coalesce(product_product_family, '') <> 'Data Transfer'
        and coalesce(line_item_usage_type, '') not like '%VpcPeering%'
)

-- Aggregates charges by invoice charge type

select
    case
        when line_item_line_item_type in ('Usage', 'SavingsPlanCoveredUsage', 'RIFee') then 'Charges'
        when line_item_line_item_type = 'RiVolumeDiscount' then 'Discount (RI Volume Discount)'
        when line_item_line_item_type = 'PrivateRateDiscount' then 'Discount (Private Rate Card)'
        when line_item_line_item_type = 'SavingsPlanNegation' then 'Savings Plan (Charges covered by Savings Plans)'
        else line_item_line_item_type
    end as "Invoice Charge Type",
    round(sum(line_item_unblended_cost), 2) as "cost"
from filtered_data
group by 1

-- If you don't have an EDP, delete everything below this line
UNION ALL

select
    'Discount (Enterprise Discount Program)' as "Invoice Charge Type",
    round(sum(edp_discount), 2) as "cost"
from filtered_data
where line_item_line_item_type in ('Usage', 'RIFee')
order by "cost" desc

CUR Legacy

Run this query in Amazon Athena. Replace the placeholders and adjust the year||month value to the invoice month you want to reconcile. For details on CUR Legacy column names, see the CUR Legacy data dictionary.

with filtered_data as (
    select
        line_item_line_item_type,
        line_item_unblended_cost,
        -- If you don't have an EDP, delete the line below and the comma above
        discount_edp_discount as edp_discount
    from <CUR_TABLE>
    where
        -- Adjust to the invoice month (format: YYYYMM)
        year||month = '<YYYYMM>'
        -- Adjust to the desired service
        and line_item_product_code = 'AmazonEC2'
        -- Adjust to your payer account ID
        -- Note: the payer field might not be available in all CUR Legacy
        -- configurations. Adjust this filter based on your Athena table schema.
        and payer = '<PAYER_ACCOUNT_ID>'
        and line_item_line_item_type not in ('DiscountedUsage', 'EdpDiscount')
        and product_product_family <> 'Data Transfer'
        and line_item_usage_type not like '%VpcPeering%'
)

-- Aggregates charges by invoice charge type

select
    case
        when line_item_line_item_type in ('Usage', 'SavingsPlanCoveredUsage', 'RIFee') then 'Charges'
        when line_item_line_item_type = 'RiVolumeDiscount' then 'Discount (RI Volume Discount)'
        when line_item_line_item_type = 'PrivateRateDiscount' then 'Discount (Private Rate Card)'
        when line_item_line_item_type = 'SavingsPlanNegation' then 'Savings Plan (Charges covered by Savings Plans)'
        else line_item_line_item_type
    end as "Invoice Charge Type",
    round(sum(line_item_unblended_cost), 2) as "cost"
from filtered_data
group by 1

-- If you don't have an EDP, delete everything below this line
UNION ALL

select
    'Discount (Enterprise Discount Program)' as "Invoice Charge Type",
    round(sum(edp_discount), 2) as "cost"
from filtered_data
where line_item_line_item_type in ('Usage', 'RIFee')
order by "cost" desc

Other services

For other services such as Amazon RDS and Amazon ElastiCache, repeat the Amazon EC2 process above, changing the Service filter to the target service. Note that not all services have a Usage Type Group for Data Transfer. In those cases, filter out Usage Type values that contain:

  • DataTransfer-Regional-Bytes
  • DataTransfer-Out-Bytes
  • -AWS-Out-Bytes
  • VpcPeering

Some services also have charges reported in separate invoice sections. For example, Amazon S3 has Amazon S3 Glacier Deep Archive charges listed separately. Adjust the filters and sums accordingly.