How to read a line item
- Timenot billed
- Bytesnot billed
- Callsnot billed
In one line
A line item is a usage type, an operation, and a charge type. Learn that grammar and the bill decodes.
Why it works that way
Nothing on your bill was written for a human to read. Every charge is a record emitted by a
metering system, and the fields on that record carry the metering system’s own vocabulary:
which meter ran, in which Region, against which API call, under which pricing rule. So
USW2-BoxUsage:m2.2xlarge is not obscurity for its own sake. It is several facts jammed into
one string, and AWS translates that exact example as “an M2 High Memory Double Extra Large
instance in the US West (Oregon) Region.”
Read it as fields instead of as a name and it decodes on sight.
The anatomy of a usage type
A usage type is a Region prefix, then a family, then an optional variant. The order is fixed.
| Piece | Example | What it tells you |
|---|---|---|
| Region prefix | USW2- |
Where the meter ran. Always first, when present. |
| Family | BoxUsage |
Which meter. Instance-hours, stored byte-hours, requests. |
| Variant | :m2.2xlarge |
Which flavour. Instance type, storage class, request tier. |
The Region prefix is a short code, and you cannot derive it from the Region name. AWS publishes the full mapping in the Regions and Availability Zones guide. A sample, including the ones that will trip you:
| Short code | Region |
|---|---|
USE1 |
us-east-1, N. Virginia |
USE2 |
us-east-2, Ohio |
USW2 |
us-west-2, Oregon |
EU |
eu-west-1, Ireland — no digit, the oldest code |
EUC1 |
eu-central-1, Frankfurt |
APN1 |
ap-northeast-1, Tokyo |
APS1 |
ap-southeast-1, Singapore |
APS3 |
ap-south-1, Mumbai — not ap-southeast-3 |
APS4 |
ap-southeast-3, Jakarta |
USE2-DataTransfer-Out-Bytes is Ohio to the internet. EUC1-EBS:VolumeUsage.gp3 is gp3
volume storage in Frankfurt. USW2-EBS:SnapshotUsage is snapshot storage in Oregon.
A missing prefix means us-east-1. AWS states this explicitly for S3: for the US East (N.
Virginia) Region the prefix is omitted, so you see TimedStorage-ByteHrs rather than
USE1-TimedStorage-ByteHrs. This is the single most useful decoding rule on this page,
because a bare Requests-Tier1 looks Region-less and is in fact your busiest Region hiding in
plain sight.
Two prefixes means two Regions, source first. APE1-USE1-AWS-In-Bytes is accelerated transfer
into Hong Kong from N. Virginia. Anything global — PublicIPv4:IdleAddress,
Global-Bucket-Hrs — carries no Region because the meter genuinely has none.
Usage type is not operation
They are two columns and they answer two different questions.
- Usage type answers which meter turned. It is the thing that has a rate attached.
- Operation answers what you did to turn it. AWS defines it as “the specific AWS
operation covered by this line item,” and it usually reads like an API name:
RunInstances,PutObject,ListBucket.
One usage type routinely carries several operations, because several unrelated things feed the
same meter. Public IPv4 is the cleanest example — the usage type
PublicIPv4:InUseAddress fans out across operations that identify what kind of thing holds
the address:
| Operation | What is holding the address |
|---|---|
RunInstances |
An EC2 public IPv4 address in a VPC |
AssociateAddressVPC |
An Elastic IP with a resource attached |
AllocateAddressVPC |
An idle Elastic IP with nothing attached |
DescribeNetworkInterfaces |
A service-managed public IPv4 address |
CreateVpnConnection |
A Site-to-Site VPN endpoint |
CreateAccelerator |
Global Accelerator |
Same rate, same usage type, six completely different remediations. Group by usage type and you learn how much; group by operation and you learn which team to talk to.
It runs the other way too. On EC2 the operation carries the software licence, so the operation
string is what separates one instance rate from another: RunInstances is Linux,
RunInstances:0002 is license-included Windows, RunInstances:0800 is Windows BYOL, and
RunInstances:0006 is Windows plus license-included SQL Server Standard. Filter on the usage
type alone and you have merged four different prices into one bucket.
What it costs
For this article, what it costs is what the fields actually say. There are two places to read them, and they are not the same product.
| Cost Explorer | Cost and Usage Report | |
|---|---|---|
| Lives | Console and API | CSV or Parquet delivered to an S3 bucket you own |
| Grain | Daily and monthly for 14 months by default | Hourly, daily, or monthly line items |
| Depth | Filter and group by a fixed set of dimensions | Every column AWS has, including resource IDs |
| Reach for it when | “What went up last week?” | “Which bucket, which hour, which operation?” |
Cost Explorer’s extras are opt-in and metered: multi-year data at monthly grain goes back 38 months, hourly granularity covers the last 14 days and is billed at $0.01 per 1,000 usage records per month, and resource-level daily data has to be enabled per service. The CUR is delivered at least once a day and is meant to be queried — Athena, Redshift, QuickSight — not read.
The fields worth knowing
| Field | What it holds |
|---|---|
lineItem/UsageType |
The decoded string above. Your primary key for “what is this.” |
lineItem/Operation |
The specific AWS operation this line covers. |
lineItem/LineItemType |
The charge type. See below — this is the one people skip. |
lineItem/LineItemDescription |
Prose. The only place credits and refunds explain themselves. |
lineItem/ProductCode |
The service, e.g. AmazonEC2. |
lineItem/ResourceId |
The instance, bucket, volume, or function — if you enabled it. |
lineItem/UsageAmount |
The quantity the rate multiplies. |
lineItem/UnblendedCost |
Rate times amount. The number you actually paid. |
lineItem/UsageAccountId |
Which member account incurred it. |
product/* |
Metadata: product/region, product/instanceType, product/servicecode, product/ProductName, product/operation. Present only when the month generated data for them. |
bill/BillingEntity |
AWS or AWS Marketplace. |
bill/InvoicingEntity |
Which AWS legal entity issued the invoice. |
Two caveats on those names. lineItem/ResourceId is blank for usage types that have no
instantiated resource behind them — data transfer, API requests — and blank for discounts,
credits and taxes, by design. And CUR 2.0 renames every column to snake case:
lineItem/UsageType becomes line_item_usage_type, product/instanceType becomes
product_instance_type. Same data, different spelling, and query code written against one
will not run against the other.
Charge types, because a bill is not only usage
lineItem/LineItemType is the field that explains why your total does not equal the sum of the
meters. AWS documents these values:
| Value | What it is |
|---|---|
Usage |
Metered usage at On-Demand rates. The three meters live here. |
Tax |
VAT, US sales tax, and the like. Added on top; no meter turned. |
Credit |
Credits AWS applied. Negative. Read the description column for why. |
Refund |
Money AWS gave back. Negative. |
Fee |
An upfront annual fee — an All Upfront or Partial Upfront reservation. |
RIFee |
The monthly recurring fee for a reservation. Posted even when it is $0. |
DiscountedUsage |
Usage that a Reserved Instance covered. Its UnblendedRate is zero. |
SavingsPlanCoveredUsage |
On-Demand cost that a Savings Plan absorbed. |
SavingsPlanNegation |
The matching negative line that cancels it out. |
SavingsPlanUpfrontFee / SavingsPlanRecurringFee |
What you actually paid for the plan. |
BundledDiscount, Discount |
Usage-based and negotiated discounts. Negative. |
The Bills console uses friendlier names for the same idea — DiscountedUsage shows up as
“Reservation applied usage”, RIFee as “Recurring reservation fee” — and the console also
uses a Subscription charge type for out-of-cycle one-time and recurring fees, which has no
identically-named counterpart in the CUR. Expect the vocabulary to shift as you move between
the console, Cost Explorer’s RECORD_TYPE, and the report.
Three consequences follow, and they are the reason a naive SUM() misleads:
- Savings Plans double-post. Covered usage appears at its full On-Demand cost, then a
SavingsPlanNegationline removes it. Filter toUsageonly and you will miss both, and your Savings Plan spend as well. - Reservations bill on the calendar, not on the workload. An upfront
Feelands the day you buy, andRIFeelands on the first of each period. Neither is proportional to anything that ran that day. - Tax is not usage. It has no usage type and no meter. It arrives at the end.
Cost Explorer’s amortized view exists precisely to undo point 2: it spreads upfront commitments across the term, so a $365 one-year All Upfront Savings Plan shows as $1 of amortized cost per day rather than $365 on one day.
Traps
Blended cost is not what you paid. Unblended cost is your account’s own usage at your
account’s own rate — the cash number. Blended cost is that same usage priced at the
organization-wide average rate, allocated back to you. AWS’s own worked example: an
organization stores 95 TB of S3 Standard across four accounts, pays $6,720 because tiering
applies once across the whole org, and every account is then shown a blended rate of
$0.070737/GB — a rate no member account ever paid, because no member account bought at that
tier. (Those tier prices are AWS’s illustration, not a current rate card.) AWS shows member
accounts unblended costs by default. If a “blended” annotation appears on a line, treat it as
informational and go back to lineItem/UnblendedCost.
Consolidated billing means your account has no free tier of its own. For billing purposes AWS treats every account in an organization as a single account. Member accounts do not reach tier thresholds individually — usage is aggregated org-wide before tiers are applied, and AWS applies the free tier to total usage across all accounts rather than to each account. This is good news at the org level and confusing at the account level: spin up a brand-new sandbox account inside a mature organization and it starts paying for egress on its first gigabyte, because the org burned the free allowance on the first of the month. Nothing is wrong. The tier was never yours.
Some charges were not priced by AWS. Check bill/BillingEntity: AWS Marketplace means a
third party set that amount and AWS is collecting it. Marketplace pay-as-you-go accumulates
into a monthly usage invoice, but one-time fees, recurring fees and payment schedules are
invoiced out of cycle — a separate invoice on its own date, appearing in the console under a
Subscription charge type. bill/InvoicingEntity may also name a different AWS legal entity
than you expect: AWS Inc., AWS India Private Limited, AWS South Africa, and others each issue
their own invoices. A bill that “arrived on the wrong day for the wrong amount from the wrong
company” is usually all three of these at once, and entirely normal.
Resource IDs are off until you turn them on. The CUR only carries
lineItem/ResourceId if you selected “Include resource IDs” when you created the report, and
Cost Explorer only shows resource-level data for services you explicitly enabled, for the last
14 days. Neither is retroactive. The month you need it is the month you did not have it.
Once a line item resolves into fields, the rest of this site becomes usable. The family part of
the usage type usually names the unit, and the unit names the meter: -Hrs and -Hours and
BoxUsage are time, -Bytes and -ByteHrs and -Scanned are bytes, Requests- and
-Units are units. It is a heuristic, not a rule — TimedStorage-ByteHrs is bytes held
over time and bills as a GB-month, and plenty of names carry no unit at all — so when a string
resists, look it up on the service page rather than guessing.
The point of getting there is that the meter names the lever. Time falls when the thing stops existing. Bytes fall when the boundary moves or the path loses a box. Units fall when you ask fewer times. Everything else on the bill — tax, credits, reservation fees, someone else’s software — is arithmetic layered on top of those three, and none of it is a lever you can pull with code.