The problem appeared when I put Amazon fee events beside a payout.
The totals didn't match.
The fee data looked detailed. The orders were there. The dates looked reasonable. But I was comparing activity from a period to cash from a settlement. Those are not the same thing.
Amazon seller fees do not live in one SP-API endpoint or report. They come from three sources, and each source answers a different question.
Settlement reports and FBA fee reports both arrive through the Reports API, so these are three answers, not three separate APIs.
If you use the wrong one, an estimate looks like a charge or a calendar period looks like a deposit.
The three places Amazon fees live
| Source | The question it answers |
|---|---|
| Financial events | What fee components were posted against financial events? |
| Settlement report | What did Amazon include in the actual payout? |
| FBA reports and Product Fees estimates | What estimated fees, storage estimates, or reimbursements sit outside a single order line? |
The source should follow the question.
For cash reconciliation, start with the settlement report.
For Amazon fees by SKU between settlements, use financial events beside your order data.
For storage, reimbursements, and forward looking fee estimates, use the specific FBA or Product Fees source.
Why don't Amazon fees match the payout?
A payout is a settlement, not a calendar period.
listFinancialEventGroups also carries fund transfer status, fund transfer date, trace id, and the account tail. That means an event group can be related to a disbursement.
I still use the settlement report as the reconciliation artifact for finance because it shows what Amazon included in the payout.
The current report type is:
GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE_V2
The older type is deprecated:
GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE
Amazon's SP-API report type strings do not have leading or trailing underscores. An underscore-wrapped name copied from an older guide will not work.
There is another trap. Settlement reports cannot be requested or scheduled through createReport.
This will not work:
POST /reports/2021-06-30/reports
with GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE_V2 as the requested report type.
Amazon generates settlement reports automatically on its own schedule. createReport does not accept settlement report types, and sellers who try it get an error saying the report type is not allowed at this time.
Instead, pull the reports Amazon has already generated with:
GET /reports/2021-06-30/reports
Use the getReports operation and filter by GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE_V2.
getReports returns report metadata, including a reportDocumentId when the document is available. Then call getReportDocument:
GET /reports/2021-06-30/documents/{reportDocumentId}
That response gives you the download URL and compression information when it applies. Fetch the document and decompress it when needed. A settlement pipeline needs both calls.
I would run that retrieval on a schedule. Do not build a job that repeatedly tries to create settlement reports. List the generated reports, keep the ones you have not processed, and use each settlement as the boundary for the deposit it represents.
Where Amazon fees by SKU come from
Use the Finances API v0 when you need posted fee detail at the financial event level.
The two main endpoints are:
GET /finances/v0/financialEventsGET /finances/v0/financialEventGroups
The fee detail in listFinancialEvents is nested. For a shipment, the documented path is FinancialEvents, then ShipmentEventList, then ShipmentEvent, then ShipmentItemList, then ItemFeeList, then FeeComponent.
The ShipmentEventList and ShipmentItemList layers are easy to miss. Code that skips them will not find the fees.
That is the useful grain for SKU margin reporting. Bring the financial events beside the matching order lines, then report the fee components by SKU.
But do not treat the latest Finances API response as final cash.
Orders from the last 48 hours might not appear in financial events yet. A dashboard that pulls only once can miss late events. A dashboard that compares today's posted events to a settlement deposit can also be correct at the row level and wrong at the cash level.
The date filters have three important rules:
GET /finances/v0/financialEvents
?PostedAfter=2026-01-01T00:00:00Z
&PostedBefore=2026-01-31T23:55:00Z
# When supplied, both dates must be at least two minutes before the request.
# Keep the PostedAfter to PostedBefore window under 180 days.
You must include PostedAfter when you include PostedBefore.
When supplied, both PostedAfter and PostedBefore must be at least two minutes before the request is submitted.
The worst trap is the 180 day range. If PostedAfter and PostedBefore are more than 180 days apart, Amazon returns an empty response instead of an error. That can look like there were no financial events when the request window was simply too wide.
Backfill financial events in windows under 180 days. For ongoing loads, revisit recent dates so events that were absent during the 48 hour lag can arrive on a later run.
The current Finances API version
The Finances API v2024-06-19 exists alongside v0.
Its listTransactions operation uses:
GET /finances/2024-06-19/transactions
It returns transactions for a date range or order without waiting for a statement period to close.
It also accepts a transactionStatus filter with three values:
RELEASEDDEFERREDDEFERRED_RELEASED
Deferred transactions are money Amazon has not released yet. That is another ordinary reason a period total and a payout disagree.
Event groups still come from the v0 listFinancialEventGroups operation. You can tie listTransactions back to one by setting relatedIdentifierName to FINANCIAL_EVENT_GROUP_ID and relatedIdentifierValue to the group id.
A pipeline written today should look at v2024-06-19 first. I treat v0 as the older surface that still holds event groups.
The fees that do not belong on one order
Some Amazon costs should not be forced into an order line.
Monthly storage is the clearest example. I use a separate itemized reimbursements report when I need each reimbursement and its reason. Estimated fees are useful for planning, but they are not posted charges.
These FBA reports are requested with createReport at POST /reports/2021-06-30/reports:
GET_FBA_ESTIMATED_FBA_FEES_TXT_DATAcontains estimated selling and fulfillment fees for inventory with active offers. Amazon updates its content at least once every 72 hours, and it can only be requested once per day per seller.GET_FBA_REIMBURSEMENTS_DATAcontains itemized reimbursements, including the reason. Amazon updates it daily.GET_FBA_STORAGE_FEE_CHARGES_DATAcontains estimated monthly inventory storage fees per ASIN.
The storage report estimate is useful for per-ASIN attribution and planning. Do not put those amounts into the period as charged costs. The actual storage charge appears as a posted service fee in the financial data and on the settlement report.
The estimated FBA fee report is not proof of what Amazon charged on a completed order. It is an estimate for active inventory.
There is also a Product Fees API operation called getMyFeesEstimateForSKU:
POST /products/fees/v0/listings/{SellerSKU}/feesEstimate
That endpoint estimates fees for a SKU at a hypothetical price. It is useful before a price change or for planning margin, but it is still an estimate. Do not reconcile it to a payout.
How I would line the sources up
First, ingest settlement reports with getReports and getReportDocument on a schedule. Use each settlement report to explain the deposit Amazon actually made.
Second, look at listTransactions for current transaction data. Use v0 financial events where you need the posted fee component grain, and use v0 event groups when you need the group that relates transactions to a disbursement. Keep revisiting the recent period because the last 48 hours can be incomplete.
Third, load the FBA reports separately. Use the storage estimate for per-ASIN attribution and planning. Use the posted service fee in the financial data and settlement report for the actual storage charge. I keep reimbursements as their own itemized adjustments with reasons. I use estimated FBA fees and getMyFeesEstimateForSKU only for planning.
This also keeps the reporting language honest:
- Estimated fee means a planning value.
- Posted fee event means a charge recorded by the Finances API.
- Settlement amount means the cash Amazon tied to a deposit.
If those three labels are collapsed into one field called amazon_fees, the numbers will keep disagreeing for reasons the dashboard cannot explain.
I put the model behind this into a repo: github.com/linerss/amazon-fee-ledger. It keeps every fee row tagged as an estimate, a posted charge, or cash, reconciles a settlement against the posted charges in its window, and fails loudly if the three ever get summed together. It runs locally on DuckDB against synthetic data, so you can see it work before pointing it at your own.
I'm not an Amazon payments specialist. I build reporting around APIs, and this is the source order I use to keep estimates, charges, and cash separate. If you have a better way to line them up, send it my way.
