The Three-Layer Fee System
Every card payment involves three fees: interchange goes to the issuing bank, assessments go to the card network, and the markup goes to your processor. The [fee optimization] framework below calculates each layer separately so you can see what you're actually paying for.
Interchange is the biggest layer and the one nobody will negotiate with you. Visa and Mastercard publish the schedule and revise it twice a year (Mastercard, 2026). The rate depends on the card type, the network, and how you presented the transaction.
Assessments are the network's own cut, a small percentage of every transaction. Everything above those two layers is the processor's markup, and that's the only part of the bill you can argue about.
The block below sets up the vocabulary the rest of the chapter uses. CardNetwork and CardType are the two keys that pick an interchange row. InterchangeRate holds a percentage and a fixed fee, because interchange has both. FeeBreakdown is the result: the three layers, the total, and the effective rate as a percentage of the amount.
PaymentFeeCalculator starts with blended pricing because that's what the merchant is on today. calculate_blended_fees is the headline formula, amount times rate plus the fixed fee. It returns zeros for interchange and assessment because on a blended contract you can't know them. The one number it does give you is the effective rate, and for a $100 order that's 3.2%. For the $5 order in the tip below, it's a different story.
from dataclasses import dataclass, field
from decimal import Decimal, ROUND_HALF_UP
from typing import Optional, Dict, List
from enum import Enum
from datetime import datetime
class CardNetwork(Enum):
VISA = "visa"
MASTERCARD = "mastercard"
AMEX = "amex"
DISCOVER = "discover"
class CardType(Enum):
CREDIT = "credit"
DEBIT = "debit"
CORPORATE = "corporate"
PREPAID = "prepaid"
@dataclass
class InterchangeRate:
network: CardNetwork
card_type: CardType
rate_percent: Decimal
fixed_fee: Decimal
category: str # e.g., "retail", "ecommerce", "card_not_present"
@dataclass
class FeeBreakdown:
interchange_fee: Decimal # Goes to issuing bank
assessment_fee: Decimal # Goes to card network
processor_markup: Decimal # Goes to your processor
total_fee: Decimal
effective_rate: Decimal # Total as percentage of transaction
amount: Decimal
class PaymentFeeCalculator:
"""
Calculate true payment processing costs across all fee layers.
Reveals actual costs versus advertised headline rates.
"""
# Standard interchange rates (simplified - actual rates vary by 300+ categories)
INTERCHANGE_RATES =
# Network assessment fees
ASSESSMENT_FEES =
def __init__(self, processor_rate: Decimal = Decimal("0.029"), processor_fixed: Decimal = Decimal("0.30")):
"""
Initialize with processor's blended rate.
Default 2.9% + $0.30 is Stripe/Square standard.
"""
self.processor_rate = processor_rate
self.processor_fixed = processor_fixed
def calculate_blended_fees(self, amount: Decimal) -> FeeBreakdown:
"""Calculate fees using processor's blended rate."""
total = (amount * self.processor_rate) + self.processor_fixed
effective_rate = (total / amount * 100).quantize(Decimal("0.01"))
return FeeBreakdown(
interchange_fee=Decimal("0"), # Unknown in blended
assessment_fee=Decimal("0"),
processor_markup=total,
total_fee=total.quantize(Decimal("0.01")),
effective_rate=effective_rate,
amount=amount
)
The $0.30 fixed fee per transaction is what kills micro-transactions. On a $5 purchase, that $0.30 alone is 6% before the percentage rate even kicks in. If more than 20% of your transactions are under $10, investigate ACH ($0.25 flat), wallet balances (zero cost), or transaction bundling to avoid bleeding margin on small payments.
Reading a Processor Statement
The effective rate is total fees divided by gross volume, and you calculate it from the statement, not the contract. Add up every fee line for the month: the percentage fees, the per-item fees, the monthly charges, the chargeback fees, anything the processor took. Divide by the gross card volume for the same month. Do it for each of the last twelve months, because one month tells you the rate and twelve tell you the trend.
For the merchant, the year looks like this:
- Percentage fees: $1M × 2.9% = $29,000
- Fixed fees: 10,000 orders × $0.30 = $3,000
- Total: $32,000, which is 3.2% of volume
That's the bottom of the 3.2-3.5% range in the warning above. International cards and currency conversion, which Chapter 9 prices at +1.5% and +1%, are what push a merchant toward the top of it.
What the statement looks like depends on the pricing model. A blended statement shows one percentage and one per-item fee, with the three layers folded together, so a rise in interchange and a rise in the processor's markup look identical. An [interchange-plus] statement lists the interchange each transaction incurred, by category, then the assessments, then the markup as its own line. It's more pages, and it's the only format in which you can see what you're paying the processor rather than the banks and the networks.
Markups hide in three places. On blended pricing they hide in the rate itself. Processors quietly raise it 0.05-0.15% a year, which is why you alert on any 0.05% move. On either model they hide in the per-item and monthly fees below the headline, each small enough that nobody escalates it. And they hide in the [downgrade], where a transaction that could have qualified for a cheap interchange category lands in a pricier one because your checkout didn't send the data the cheap category requires.
On interchange-plus you see the downgrade as volume landing in the wrong category. On blended you see nothing, the processor absorbs it, and the only place that cost can go is into your rate at the next review.
Two lines confuse everyone. Assessments are the network's percentage of your volume, 0.13-0.15% in the takeaways. Network fees are everything else the networks charge, billed alongside the assessments, and Chapter 3's definition is the accurate one: the fees beyond the assessment fees. Both are pass-through on interchange-plus and invisible on blended, and neither is negotiable. If either line grows faster than your volume, ask the processor to point you at the network's published change.
Chapter 20 gets this data out of the statement and into your books: revenue at gross, fees in their own expense account. Its monthly fee reconciliation is what catches the retroactive adjustments it puts at 0.1-0.3% of volume. Do that once and the effective rate becomes a query you run, instead of a quarterly archaeology project.
Stripe's published rates, as an example of how add-ons stack. Chapter 9.
| Item | Cost | Notes |
|---|---|---|
| Cards, US online | 2.9% + $0.30 | The headline |
| International cards | +1.5% | Card issued outside your account's country |
| Currency conversion | +1% | Charge currency differs from your settlement currency |
| Stripe Billing | +0.7% of subscription volume | Subscriptions, dunning, proration, test clocks |
| Stripe Invoicing | +0.4-0.5% per paid invoice | If you only send invoices |
| Stripe Tax | +0.5% per transaction | Only in jurisdictions where you're registered to collect |
| Radar | Included | Radar for Fraud Teams (rules, review queue) adds $0.02 per screened transaction on standard pricing |
| Connect, Express or Custom accounts | $2 per active account per month, plus 0.25% + $0.25 per payout | Standard accounts cost the platform nothing |
| Disputes | $15 each | Not refunded when you win |
| Checkout, Payment Element, Payment Links, Link | No extra fee |