Two eBay research tools can show different sold-price summaries without either arithmetic calculation being wrong. One may include shipping, another may include multi-item lots, and a third may summarize a smaller or older set of listings. Before comparing the headline numbers, compare what went into them.
This guide turns a disagreement into an audit. It explains the observations SoldFetch exposes, works through a small synthetic dataset, and provides an offline Python example that reproduces the calculations. The goal is to make each number explainable before using it in a sourcing or pricing decision.
Every amount in the worked example is synthetic. It is not a current marketplace benchmark or a recommended price.
Start with the meaning of the observed price
A row returned by SoldFetch sold search contains soldPrice and soldCurrency. Despite the field name, the amount is a displayed listing price, not an independently verified buyer payment. Keep the adjacent quality metadata in your database and export.
| Field | Interpretation |
|---|---|
quality.priceBasis |
displayed_listing_price or range_lower_bound |
quality.acceptedOfferAmount |
Null; accepted-offer amount is unavailable |
quality.saleDateVerified |
False; reported sale dates are unverified |
quality.exactProductMatchVerified |
False; product equivalence is unverified |
bestOfferAccepted |
Null; do not interpret an unknown value as false |
If a listing involved an accepted offer, the displayed amount may not reveal that agreement. SoldFetch does not supply the undisclosed accepted-offer amount. Do not estimate one by applying an arbitrary discount to every displayed price.
Also distinguish a sold-search row from an item lookup that says a listing has ended. An ended listing is not proof of a sale. Keep the collection route and listingType so a later analyst can see which kind of observation produced the number.
Make shipping a deliberate choice
An item price and an item-plus-shipping amount answer different questions. If one report uses soldPrice and another uses totalPrice, they can disagree even when they contain the same listings.
SoldFetch provides shippingPrice, shippingCurrency, shippingType, and, where it can be formed from compatible amounts, totalPrice. A null shipping value is unknown. It is not zero. Explicit free shipping is a different case and can be represented as zero with the matching currency.
Choose one basis for a summary. For item-plus-shipping analysis, require a usable total and compatible item and shipping currencies. Report how many rows become unavailable under that rule. Taxes, import costs, destination-specific delivery differences, and other buyer expenses are not established by this field, so avoid calling the result a universal checkout total.
If a sample changes substantially when you require known shipping, preserve both the item-only and item-plus-shipping reports with clear labels. Their different sample sizes explain why subtracting one median from the other is not necessarily a typical shipping charge.
Separate ranges, lots, and product variants
A displayed price range is marked priceBasis="range_lower_bound". A lower bound should not be treated as one complete product's price in a single-amount median. Exclude it, or design an analysis that explicitly represents ranges.
Lots require a different product definition. A two-unit lot may include two identical working products, mixed conditions, or one useful unit and one parts donor. Dividing its total by two does not establish a comparable per-unit observation. Keep lot size and contents in the review evidence, and include lots only in a deliberately separate cohort.
The same principle applies to storage capacities, accessories, graded cards, bundles, and repair-only electronics. The keyword is a way to find candidates; it is not evidence that all candidates are interchangeable. The exactMatch request option removes explicitly flagged loose matches but does not guarantee exact product identity.
Use local include, exclude, and hold decisions. Keep a reason for each one, and retain source URLs, titles, available item details, and original responses. The item API guide covers selective enrichment for difficult candidates.
Reproduce a disagreement with six synthetic rows
Assume one marketplace, USD throughout, and a reviewed target product. The following records are deliberately synthetic and use letter labels rather than real listing IDs:
| Row | Displayed item price | Shipping | Product evidence | Price basis |
|---|---|---|---|---|
| A | 100.00 | 10.00 | One matching unit | Single displayed price |
| B | 110.00 | 0.00 | One matching unit | Single displayed price |
| C | 90.00 | Unknown | One matching unit | Single displayed price |
| D | 200.00 | 0.00 | Two-unit lot; excluded | Single displayed price |
| E | 80.00 lower bound | 0.00 | Target appears in a range; excluded | Range lower bound |
| F | 120.00 | 0.00 | One matching unit | Single displayed price |
Accepted-offer amounts are unknown for every row. Nothing in this table establishes a verified transaction amount or date.
The reviewed single-unit item-only sample contains A, B, C, and F. Its sorted amounts are 90, 100, 110, and 120, giving a median of 105.00. Requiring known shipping removes C. The remaining item-plus-shipping amounts are 110, 110, and 120, giving a median of 110.00.
Both summaries are correct descriptions of their stated synthetic samples. Neither is a verified transaction-price median. The five-dollar difference reflects both the amount definition and the changed membership; it is not a direct estimate of typical shipping.
Run the audit arithmetic offline
The companion Python example reproduces the table with Decimal. It accepts an explicit set of reviewed single-unit IDs, excludes range lower bounds, rejects missing or invalid amounts, checks shipping currency for totals, and deduplicates rows.
python3 ebay-sold-price-differences.py
Its output labels the examples synthetic and reports the two medians and sample sizes. Assertions check the worked arithmetic, empty samples, repeated rows, invalid amounts, and missing or incompatible shipping. The script performs no authenticated requests and consumes no API units.
For a real workflow, store the review journal beside the raw collection and pass only approved IDs into the calculation. Preserve the exclusion counts in the report. If two colleagues get different outputs, compare their cohort policy, review decisions, amount basis, and source snapshots before changing the formula.
Do not overwrite old evidence with the newest response. Listing content can change or become unavailable, and cached observations can have different timestamps. Keeping the original run makes a previous report reproducible even after the source has moved on.
Inspect time windows and small samples
Search rows carry a source observation timestamp, and sold-search rows may include supplier-reported endedAt. That date is unverified. “Observed on October 24” and “sold on October 24” are different claims; use the first when that is what your evidence supports.
Two runs can return different populations because of search ordering, pagination, changing listings, caching, or a different query. Record the parameters, page budget, pages completed, fetchedAt, row timestamps, and stop reason. Pagination is inferred, and repeated or empty pages should end a bounded sweep.
A tiny sample is especially sensitive to membership. In the synthetic item-only set, dropping the 90-dollar row changes the median from 105 to 110 without changing any remaining price. That is a sample-composition change, not evidence of a market-wide increase.
Show the accepted count beside the median. Add a visible limited-sample state when too few comparable observations remain under your policy. A clean decimal presentation should not hide weak or incomplete evidence.
Use an audit checklist before publishing a number
Before a report leaves the analysis notebook, confirm these parallel questions:
- Are the marketplace, currency, product variant, condition, and bundle policy consistent?
- Does the label say displayed sold-search price, with accepted-offer amounts unknown?
- Is the amount basis item-only or item-plus-shipping, and are null values preserved?
- Were range lower bounds, unresolved matches, and lots handled explicitly?
- Were repeated IDs removed within the collection run?
- Are the observation timestamps, page budget, and collection completeness available?
- Can a reviewer inspect included rows, exclusions, and the original evidence?
Keep the answers in the report's metadata, not only in an analyst's memory. A disagreement should be resolvable by inspecting the evidence and method. If it remains unresolved, show the uncertainty instead of selecting the more attractive number.
Build a report whose limitations travel with it
An exported CSV should include listing identity, source URL, amount, currency, shipping fields, price basis, quality flags, source timestamp, and local review decision. A screenshot of a median loses that context; a durable report keeps it attached.
Create a SoldFetch account to collect a small candidate sample, and check capabilities and the Search API reference before running it. For repeated comparisons, use the storage and collection patterns in Build an eBay Price Tracking Workflow.
The practical goal is a number that another person can reproduce and understand. When the data cannot support a stronger claim, a narrower label is part of a useful result.



