Amazon SP-API 9 min read

Amazon Data Kiosk netProceeds Is Not Profit (Cost of Goods Is Missing)

Data Kiosk's economics dataset returns netProceeds populated on every row and costOfGoodsSold null on every row. Net proceeds is net sales minus fees minus ad spend, and nothing else. Here is the exact formula, how to verify it against your own account, and why Sponsored Products spend arrives without an Ads API call.

Updated Aug 2026
Amazon Data Kiosk netProceeds Is Not Profit (Cost of Goods Is Missing)

netProceeds Is Not Profit #

You run the Data Kiosk economics query, get a clean response back, and notice two things at once. Every cost field is empty:

"cost": {
  "costOfGoodsSold": null,
  "miscellaneousCost": null,
  "fbaCost": null,
  "mfnCost": null
}

And netProceeds has a number in it anyway.

Both cannot be true of a profit figure. netProceeds is net sales minus Amazon's fees minus your ad spend. Your cost of goods is not in it, and no part of the response tells you that.

In one line

netProceeds.total = sales.netProductSalesΣ feesΣ ads. Cost of goods is never subtracted.

This matters because the field is not null. It is a number with a currency code attached, sitting in a block called net proceeds. Point a dashboard at it and every margin you display is overstated by exactly what you paid your supplier. Silently, and consistently, on every row.

Verified against a live seller account in August 2026 on the Seller Economics schema v2024-03-15. The identity held on every row returned, to a residual of 0.0000.

What One Economics Query Actually Returns #

Before the catch, the part that is genuinely good. A single economics query returns most of a per-ASIN P&L in one response, aggregated the way you asked for it.

In the responseWhere you would otherwise get it
Units, revenue, refunds, average selling priceOrders API or Sales API
Every fee, itemised, with per-unit amountsFinances API, at transaction level, aggregated by you
Sponsored Products spendAdvertising API: different portal, different application, different approval
netProceeds, per unit and totalcomputed by you, then reconciled
Three separate Amazon APIs on the left converging into a single Data Kiosk economics query on the right Orders / Sales API units, revenue Finances API fees, per transaction Advertising API separate portal, separate approval Data Kiosk economics one GraphQL query SP-API credentials only per ASIN, per month sales fees ad spend

You choose the grain in the query itself: DAY, WEEK, MONTH or RANGE, against PARENT_ASIN, CHILD_ASIN or MSKU. That is the difference between Data Kiosk and the Reports API: with a report, Amazon picked the columns and the buckets; here you do.

Key mental model: Data Kiosk borrows Amazon Marketing Cloud's workflow: you author a query, submit it, poll, then download the result. The freedom is narrower though. AMC gives you SQL over tables; Data Kiosk gives you field selection over a fixed schema, so you shape the report but cannot widen its scope. The asynchronous shape is identical to reports, so the create-poll-download pattern applies unchanged.

Why costOfGoodsSold Comes Back Null #

It is not a bug, a permission gap, or a missing role. Amazon does not know what you paid your supplier. There is no transaction on your seller account that records it, because the purchase happened somewhere else entirely.

The schema says so plainly. The PerUnitCost type carries this description: the item level per unit cost provided by seller. Fields in this type will be null if not provided by the seller.

Cost of goods reaches Amazon only if someone types it into Seller Central, per SKU, under Manage Inventory. Most accounts have never had it entered. On an account that has not, all four cost fields return null on every row, in every marketplace, for every date range, and nothing in the response marks the resulting netProceeds as incomplete.

Net proceeds equals net sales minus fees minus ad spend. Cost of goods is subtracted only afterwards and Amazon does not supply it. Net sales Fees Ad spend = netProceeds Amazon returns this − cost of goods you supply this, or it stays null

Gotcha: a null cost field is loud, so you notice it and handle it. A populated netProceeds built from those nulls is silent. It is the second one that reaches a dashboard and stays there.

How to Verify the Formula on Your Own Account #

Do not take the formula on trust. It is three lines of arithmetic against a response you already have.

Request sales, fees, ads and netProceeds together, aggregated monthly by child ASIN:

query Economics {
  analytics_economics_2024_03_15 {
    economics(
      startDate: "2026-05-01"
      endDate: "2026-07-31"
      aggregateBy: { date: MONTH, productId: CHILD_ASIN }
      marketplaceIds: ["A1F83G8C2ARO7P"]
    ) {
      childAsin
      sales { netProductSales { amount } netUnitsSold }
      fees { feeTypeName charges { aggregatedDetail { totalAmount { amount } } } }
      ads  { adTypeName charge { totalAmount { amount } } }
      cost { costOfGoodsSold { amount } }
      netProceeds { total { amount } }
    }
  }
}

Then check the identity row by row:

def amount(node):
    return float((node or {}).get("amount") or 0.0)

for row in rows:
    net_sales = amount(row["sales"]["netProductSales"])
    fee_total = sum(amount(c["aggregatedDetail"]["totalAmount"])
                    for f in row.get("fees") or []
                    for c in f.get("charges") or [])
    ad_total  = sum(amount(a["charge"]["totalAmount"])
                    for a in row.get("ads") or [])

    reported = amount(row["netProceeds"]["total"])
    derived  = net_sales - fee_total - ad_total

    assert abs(reported - derived) < 0.01, row["childAsin"]

It holds exactly. Not approximately, not within rounding. The residual is zero on every row.

The sign convention that breaks the first attempt

Fees and ad charges come back positive. They are charges, not signed ledger adjustments, so you subtract them yourself. Only reimbursements and refunded fees, such as FBAInventoryReimbursement and RefundedReferralFee, carry a negative sign.

Write net_sales + fee_total + ad_total on the assumption that Amazon has already signed them and the identity fails on most rows while still matching on the handful where charges happen to net out. That partial match is worse than a clean failure, because it looks like a rounding problem rather than a sign error.

Where the Sponsored Products Spend Comes From #

The surprising part of the response is that ad spend is in it at all. No Ads API application, no profile_id, no second OAuth flow. Three SP-API credentials and a Data Kiosk query return Sponsored Products spend per ASIN per month.

That crosses a real boundary. Advertising and Selling Partner are separate developer programmes with their own application and approval process. So it is worth knowing why the wall has a hole in it.

It is not the advertising system. It is the billing ledger. In the schema, ads[].charge is typed AggregatedDetail, the identical type used by ReferralFee and FbaFulfilmentFee. Request the full type on both and the same sub-fields populate:

Sub-fieldads[].chargeReferralFee
amountpopulatedpopulated
amountPerUnitpopulatedpopulated
promotionAmountpopulatedpopulated
taxAmountpopulatedpopulated
totalAmountpopulatedpopulated
quantitypopulatedpopulated
amountPerUnitDeltanullnull

Same shape, same one null. Amazon's own wording follows: the help page linked from the schema is titled supported fee types and advertisement charge types. To the ledger, your ad spend is a charge like any other.

What quantity means on an ad charge

quantity is populated on ad rows, and it is not your unit count. On rows checked in August 2026 it ran into the thousands where units sold were in the hundreds, and on one row it was lower than units sold, which rules out any units-based reading. Divide totalAmount by quantity and the result lands just under £1 on every row, holding within about 15% across the sample.

That is a cost per click. Sponsored Products bills per click, so quantity is billable clicks and amountPerUnit is your effective CPC, available for free, without touching the Ads API.

The limit worth knowing: you get spend, clicks and CPC, because those are facts on a bill. You get no impressions, no ACOS, no keywords, no campaigns and no ad groups, because none of those are charges. For performance data the Ads API is still the only route.

Building a Dashboard That Does Not Drift #

The lesson generalises past this one field. A populated number from a first-party API is not the same as the number you want, and the gap is rarely documented.

  1. Never surface a vendor's derived field as your own metric

    Store netProceeds if you like, but label it net proceeds. The moment it appears in a column headed Profit or Margin, you have made a claim Amazon never made.

  2. Recompute from components you control

    You have net sales, itemised fees and ad spend in the same row. Compute margin yourself from those plus your own cost of goods, held in your own system where you can correct it.

  3. Assert the identity in your pipeline, not once by hand

    The check above is cheap enough to run on every ingest. If Amazon ever changes what goes into netProceeds, a failing assertion tells you the week it happens rather than the quarter someone notices.

  4. Treat null and zero as different

    A null cost field means unknown. Coercing it to zero at ingest converts a known unknown into a confident wrong answer, which is the worse of the two.

This is the same class of problem as a dashboard whose totals never quite agree with Seller Central: not a bug, but two systems computing subtly different things. More on that in why your custom dashboard does not match Seller Central.

Building seller reporting and want the numbers to survive an audit rather than merely render? Tell me what you are pulling and I will tell you where it drifts.

FAQ #

Does Amazon Data Kiosk netProceeds include cost of goods?

No. netProceeds is net product sales minus Amazon fees minus advertising charges. Cost of goods is excluded, and on accounts that have never entered COGS in Seller Central the entire cost block returns null while netProceeds still returns a value.

Why is costOfGoodsSold null in the Data Kiosk economics dataset?

Because it is seller-supplied. The PerUnitCost type in the Seller Economics v2024-03-15 schema states that its fields are null if not provided by the seller. Amazon has no record of what you paid your supplier unless it is entered per SKU in Seller Central.

Can I get Sponsored Products spend without the Advertising API?

Yes. The Data Kiosk economics dataset returns Sponsored Products charges per ASIN using SP-API credentials alone, because the figures come from your seller billing ledger rather than the advertising system. You get spend, billable clicks and an effective cost per click, but no impressions, ACOS, keywords or campaign structure.

Why do Data Kiosk fees come back as positive numbers?

They are charges rather than signed ledger adjustments, so you subtract them when computing net proceeds. Reimbursements and refunded fees such as FBAInventoryReimbursement and RefundedReferralFee are the exceptions and carry negative values.

How long does a Data Kiosk query take to run?

It is asynchronous, like the Reports API. Queries in August 2026 moved from IN_QUEUE to IN_PROGRESS to DONE in roughly 33 seconds for a three-month, ASIN-level economics request. Results carry a 30-day retention window, so warehouse anything you intend to keep.

Don't want to build this yourself?

I set this up for sellers and agencies every week. Book a free 30-minute audit of your Amazon data & PPC setup — you'll leave with a plan either way, whether we work together or not.

Found this helpful? Share it:

WhatsApp