← Blog

FinOps · Field guide

Cost per transaction on AWS: how to measure it and why it drifts

Your AWS bill tells you what you spent. Cost per transaction tells you whether the platform gets more efficient as the business grows. For a payments company, that is the number a CFO, a bank partner and an acquirer will eventually ask for.

By Ribau · · Updated · 11 min read

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.

UnitWhat it countsGood forWatch out for
Authorization requestsEvery request your platform answers, approved or declinedGateways and processors where the request path is the main costRetries and duplicate requests inflate the count and flatter the unit cost
Captured paymentsPayments that move moneyComparing cost with revenue, since fees are usually earned on capturesDeclines still cost money to process but disappear from the denominator
Settled transactions incl. refundsEvery money movement that reaches settlement and reconciliationPlatforms where settlement, reconciliation and reporting dominate costBatch timing shifts volume between months; use a rolling average
Active merchants or accountsCustomers with activity in the monthSoftware platforms priced per customer rather than per paymentHides 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.

CategoryTypical servicesScales with volume?How to separate it
Transaction pathAPI layer, compute, queues and streams, transactional databases, cachesYes, directlyDedicated production accounts, or a workload tag on every resource
Data and reportingData lake storage, ETL jobs, warehouse or query engine, BIPartly: storage grows with history, jobs with volumeSeparate data account, or a workload tag value of its own
Shared platformNetworking, NAT gateways, logging and monitoring, security tooling, CI/CDPartlyA shared-services account, then allocated in step 3
Non-productionDevelopment, test and staging environmentsNoSeparate accounts per environment
Account-level chargesAWS Support, Marketplace subscriptions, taxesNoExclude 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.

RuleHow it worksUse it for
ProportionalShared cost split in the same ratio as each workload's direct costMost shared platform cost; the simplest rule to defend
Usage-basedSplit by a measured driver: GB of logs ingested, GB through NAT, requests through a load balancerLarge shared items with a clear driver, such as logging and data transfer
Fixed percentageAn agreed share, for example 70% transaction path and 30% dataSmall items, or when no driver is measurable yet
Even splitEqual share per workloadRarely; 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.

LineTodayIn 12 months
Captured payments per month12,000,00015,000,000 (+25%)
Total AWS spend per month$85,000$119,000 (+40%)
Share on the transaction path, incl. allocated shared cost60%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.

CauseWhat you see in the dataWhat usually fixes it
Capacity sized for peak, all monthCompute and database cost flat across the month while volume swings 2–3× between quiet days and month-endAutoscaling on the real driver (queue depth, requests), scheduled scaling for known peaks, serverless for spiky components
Data copied instead of sharedStorage and ETL cost growing faster than transaction volumeOne governed copy of transaction data in the lakehouse, read by every consumer; retention rules per dataset
Data transferRising DataTransfer and NAT gateway processing lines, often in the shared-platform accountKeeping chatty services in the same Availability Zone where resilience allows, VPC endpoints for AWS services, compression
Log and metric volumeLogging cost per 1,000 transactions rising release after releaseLog levels by environment, sampling for high-volume debug data, shorter retention, archive to S3
Idle environmentsNon-production accounts costing the same at weekends as on weekdaysSchedules that stop non-production outside working hours; ephemeral test environments
Old instance and storage generationsThe same workload costing more than a recent equivalent on current hardwarePlanned upgrades to current instance families, Graviton where the software supports it, gp3 instead of gp2 volumes
No ownerLarge untagged or shared buckets that nobody reviewsA 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:

  1. Refresh the numbers. Last month's cost by workload and component, the transaction count, the unit cost and the three-month average.
  2. Compare against the target. Agree a target for the year, for example "flat or falling cost per 1,000 payments while volume grows 25%".
  3. Look at the three biggest movers. The components whose cost per 1,000 rose most since last month, with their owners in the room.
  4. Agree one or two actions. Each with an owner, an expected effect on unit cost and a date.
  5. 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.

StageWhat existsTypical time to reach it
1. VisibleOne written transaction definition, a monthly unit cost from accounts and a few tags, untagged spend known2–4 weeks
2. OwnedShared cost allocated by written rules, unit cost per component, named owners, a monthly review with actions1–3 months
3. Designed inArchitecture decisions state their expected effect on unit cost; targets per component; unit cost in the board pack6–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.

Where to start

Cloud Health, FinOps & Governance Review

Where we look first →