Why the total bill is the wrong number
A growing payments business should see its AWS bill grow. The useful question is whether it grows in proportion to volume, faster or slower. A total hides that answer; a unit cost exposes it.
When spend rises 40% in a year and transactions rise 25%, the platform is getting less efficient, even if nobody did anything visibly wrong. The bill looks like growth. The unit cost shows that each transaction now costs about 12% more to process.
Unit cost is also the number other people will ask for. A CFO uses it to model margins at the next volume tier. A sponsor bank or a large merchant may ask how cost behaves at peak. An acquirer's technical due diligence will try to rebuild it from your bill. It is better to have your own number, with your own definition, before someone else builds theirs.
The method below takes four steps. None of them needs a new tool: AWS billing data, a query engine and a spreadsheet are enough to start.
Step 1: define the transaction, once
Pick one unit and keep it stable. Different definitions produce very different numbers from the same bill, and a definition that changes between quarters makes the trend meaningless.
| Unit | What it counts | Good for | Watch out for |
|---|---|---|---|
| Authorization requests | Every request your platform answers, approved or declined | Gateways and processors where the request path is the main cost | Retries and duplicate requests inflate the count and flatter the unit cost |
| Captured payments | Payments that move money | Comparing cost with revenue, since fees are usually earned on captures | Declines still cost money to process but disappear from the denominator |
| Settled transactions incl. refunds | Every money movement that reaches settlement and reconciliation | Platforms where settlement, reconciliation and reporting dominate cost | Batch timing shifts volume between months; use a rolling average |
| Active merchants or accounts | Customers with activity in the month | Software platforms priced per customer rather than per payment | Hides the effect of a few very large customers |
Most payments companies end up with one primary unit and one secondary unit. For example, captured payments for the margin view and authorization requests for the engineering view. Write each definition down next to the metric, with the system it is counted from, so that the number means the same thing in a year.
Step 2: separate the transaction path from everything else
Not every dollar of AWS spend serves transactions. Analytics, development environments and back-office tools are real costs, but they do not scale with volume in the same way. Mixing them in makes the unit cost noisy and hard to act on.
| Category | Typical services | Scales with volume? | How to separate it |
|---|---|---|---|
| Transaction path | API layer, compute, queues and streams, transactional databases, caches | Yes, directly | Dedicated production accounts, or a workload tag on every resource |
| Data and reporting | Data lake storage, ETL jobs, warehouse or query engine, BI | Partly: storage grows with history, jobs with volume | Separate data account, or a workload tag value of its own |
| Shared platform | Networking, NAT gateways, logging and monitoring, security tooling, CI/CD | Partly | A shared-services account, then allocated in step 3 |
| Non-production | Development, test and staging environments | No | Separate accounts per environment |
| Account-level charges | AWS Support, Marketplace subscriptions, taxes | No | Exclude taxes; treat support as shared |
Accounts give the cleanest boundary because nothing can be untagged inside them. Tags give finer detail within an account. In practice you need both: accounts per environment and per major workload, and a small set of mandatory tags such as workload, component and owner.
Two practical details matter here. First, a tag only appears in billing data after it has been activated as a cost allocation tag in the Billing console, so activate the tags early. Second, an untagged resource is a cost nobody owns. Track the share of spend that is untagged and treat it as a number to drive down, not a footnote.
For containers, enable split cost allocation data for Amazon ECS or Amazon EKS. It breaks shared cluster cost down to the task or pod, so a cluster that runs both payment services and reporting jobs can be divided correctly.
The billing source is the AWS Cost and Usage Report, delivered as a Data Export to Amazon S3 and queried with Amazon Athena. A first query only needs to group cost by month and by workload tag:
-- Monthly cost by workload tag (CUR 2.0 export queried in Athena)
SELECT date_trunc('month', line_item_usage_start_date) AS month,
coalesce(resource_tags['user_workload'], 'untagged') AS workload,
round(sum(line_item_unblended_cost), 2) AS cost_usd
FROM cur2
WHERE line_item_line_item_type NOT IN ('Tax', 'Credit', 'Refund')
GROUP BY 1, 2
ORDER BY 1, 3 DESC;
Unblended cost is fine for a first look. For the real metric, switch to amortized cost, which spreads upfront Savings Plan and Reserved Instance payments across the months they cover. The AWS CUR Query Library has a ready-made amortized cost expression. Credits are excluded on purpose: a one-off credit makes a month look efficient when nothing changed.
Step 3: allocate shared costs with an explicit rule
Networking, observability, security tooling, data transfer and support are shared by every workload. They still belong in the unit cost, because the transaction path could not run without them. What matters is that the allocation rule is written down and applied the same way every month.
| Rule | How it works | Use it for |
|---|---|---|
| Proportional | Shared cost split in the same ratio as each workload's direct cost | Most shared platform cost; the simplest rule to defend |
| Usage-based | Split by a measured driver: GB of logs ingested, GB through NAT, requests through a load balancer | Large shared items with a clear driver, such as logging and data transfer |
| Fixed percentage | An agreed share, for example 70% transaction path and 30% data | Small items, or when no driver is measurable yet |
| Even split | Equal share per workload | Rarely; only when workloads are of similar size |
AWS Cost Categories can apply these rules for you. A cost category groups accounts and tags into business-level buckets, and its split charge rules can distribute a shared bucket proportionally, evenly or by fixed percentages. The result appears in Cost Explorer and in the Cost and Usage Report, so finance and engineering see the same allocation.
A simple rule applied consistently beats a precise rule nobody trusts. Start with proportional allocation, move the two or three largest shared items to usage-based rules once you can measure their drivers, and record every change to the rules with its date.
Step 4: measure it monthly against volume
The metric itself is simple:
Cost per 1,000 transactions = transaction-path AWS cost (amortized, incl. allocated shared cost) ÷ transactions × 1,000
Per 1,000 rather than per transaction keeps the number readable: $4.25 per 1,000 is easier to discuss than $0.00425 per transaction.
Plot it monthly next to volume. Flat or falling unit cost while volume grows is the healthy pattern. Rising unit cost is a signal to look at architecture, not only at discounts. Three habits make the trend reliable:
- Use the same month boundaries for cost and volume. Billing data is in UTC; make sure the transaction count is too.
- Keep a rolling three-month average beside the monthly value. Month-end batches, holidays and a single incident can move one month a lot.
- Split fixed and variable cost once a quarter. Plot monthly cost against monthly volume. The point where the line meets zero volume is your fixed cost; the slope is the cost of each additional 1,000 transactions. A high fixed share means unit cost will fall naturally with growth. A steep slope means each new customer costs almost as much as the last.
A worked example
Take a payments platform processing 12 million captured payments a month, with an AWS bill of $85,000 a month. These are the default values in our cost per transaction calculator, so you can follow along and then replace them with your own.
| Line | Today | In 12 months |
|---|---|---|
| Captured payments per month | 12,000,000 | 15,000,000 (+25%) |
| Total AWS spend per month | $85,000 | $119,000 (+40%) |
| Share on the transaction path, incl. allocated shared cost | 60% | 60% |
| Transaction-path cost per month | $51,000 | $71,400 |
| Cost per 1,000 payments | $4.25 | $4.76 (+12%) |
Volume grows 25% but spend grows 40%, so each payment costs 12% more to process a year from now. At 15 million payments a month, that difference is about $7,650 a month, or roughly $92,000 a year, compared with holding unit cost flat at $4.25.
The finding is not "spend less". It is "find out why each payment got more expensive". The next section lists the usual reasons.
Why unit cost drifts upward
In our experience the same few causes explain most of the drift. Each one leaves a recognizable trace in the billing data.
| Cause | What you see in the data | What usually fixes it |
|---|---|---|
| Capacity sized for peak, all month | Compute and database cost flat across the month while volume swings 2–3× between quiet days and month-end | Autoscaling on the real driver (queue depth, requests), scheduled scaling for known peaks, serverless for spiky components |
| Data copied instead of shared | Storage and ETL cost growing faster than transaction volume | One governed copy of transaction data in the lakehouse, read by every consumer; retention rules per dataset |
| Data transfer | Rising DataTransfer and NAT gateway processing lines, often in the shared-platform account | Keeping chatty services in the same Availability Zone where resilience allows, VPC endpoints for AWS services, compression |
| Log and metric volume | Logging cost per 1,000 transactions rising release after release | Log levels by environment, sampling for high-volume debug data, shorter retention, archive to S3 |
| Idle environments | Non-production accounts costing the same at weekends as on weekdays | Schedules that stop non-production outside working hours; ephemeral test environments |
| Old instance and storage generations | The same workload costing more than a recent equivalent on current hardware | Planned upgrades to current instance families, Graviton where the software supports it, gp3 instead of gp2 volumes |
| No owner | Large untagged or shared buckets that nobody reviews | A named owner per component, and the monthly review described below |
Discount instruments such as Savings Plans and Reserved Instances recover part of the cost once. They are worth having for the stable base. But they lower the level of the line, not its slope. Sustained improvement comes from architecture: workloads sized for their real pattern, fewer copies of data, and owners who see their unit cost every month.
Running the monthly review
The metric only changes behavior if someone looks at it on a fixed date and acts on it. A 30-minute review in the first week of each month is enough:
- Refresh the numbers. Last month's cost by workload and component, the transaction count, the unit cost and the three-month average.
- Compare against the target. Agree a target for the year, for example "flat or falling cost per 1,000 payments while volume grows 25%".
- Look at the three biggest movers. The components whose cost per 1,000 rose most since last month, with their owners in the room.
- Agree one or two actions. Each with an owner, an expected effect on unit cost and a date.
- Check last month's actions. Did the unit cost move as expected? If not, why not?
Keep the output in one place, such as a shared page with the chart and a short action log. Over a year it becomes the history a CFO, a board or an acquirer will ask to see.
What good looks like
Most teams move through three stages. You do not need the third to get value from the first.
| Stage | What exists | Typical time to reach it |
|---|---|---|
| 1. Visible | One written transaction definition, a monthly unit cost from accounts and a few tags, untagged spend known | 2–4 weeks |
| 2. Owned | Shared cost allocated by written rules, unit cost per component, named owners, a monthly review with actions | 1–3 months |
| 3. Designed in | Architecture decisions state their expected effect on unit cost; targets per component; unit cost in the board pack | 6–12 months |
The FinOps Foundation describes the same idea as unit economics: connecting cloud spend to the business value it produces. For a payments company, the transaction is the natural unit to start with.
Questions we hear
Should cost per transaction include people costs?
Not in this metric. Keep it to cloud cost so that engineering can act on it directly. A fuller unit cost that adds licenses, third-party services and people is useful for pricing, but it belongs in a separate finance model.
What if our tagging is poor today?
Start with accounts. If production, data and non-production already live in separate accounts, you can produce a usable first number this month and improve tag coverage in parallel. Report the untagged share alongside the unit cost so everyone knows how precise it is.
How do we treat Savings Plans and Reserved Instances?
Use amortized cost, so each month carries its share of upfront payments and its discounted rate. Otherwise the month you buy a commitment looks expensive and the following months look artificially cheap.
What is a good cost per 1,000 transactions?
There is no useful industry benchmark, because architectures, definitions and scope differ too much. Compare yourself with your own trend and with your own revenue per transaction. The question is whether the line is flat or falling while volume grows.
Does this work for SaaS or commerce?
Yes, with a different unit: cost per customer for a SaaS platform, cost per order for a commerce platform. Shared infrastructure makes attribution harder; our guide to cost per customer in a multi-tenant SaaS covers that case.
How long does it take to set up?
A first version from existing accounts and billing data usually takes two to four weeks of part-time work. Shared-cost rules and a monthly review take another month or two to settle.