I wanted one boring, reliable number for resale items: what they actually sold for recently, not what people are asking. So I built SoldSignal, a small weekly index, and opened the data as a free API. No key, no signup, CORS open.

What the API returns

GET https://www.aiplannermail.com/api/v1/items.json gives the current week (right now 2026-W45, 52 items across sneakers, watches, collectibles, gaming and fashion). Each item has:

Field Meaning
price the headline median for the week
priceType SOLD or ASK, never mixed in one number
sampleSize how many sales or listings the median is based on
category, slug, name what it is
href a per-item JSON with more detail

The per-item file (/api/v1/items/<slug>.json) adds the basis in plain words, retail and premium %, week-over-week change, per-platform medians, a lowSample flag, and the net payout after marketplace fees for each tracked platform.

Example (real, this week): Air Jordan 4 "Bred Reimagined", median $251 SOLD from 13 data points on GOAT, retail $215, about $215.71 net after GOAT fees.

SOLD vs ASK, never mixed

This was the main design rule. Asking prices are cheap to collect and often far from reality, so each item gets exactly one price type:

  • SOLD (43 of 52 items this week): medians of recorded sales (GOAT last sales per size, Mercari sold listings).
  • ASK (9 items, mostly watches): medians of live listings, labeled as asks, because there is no reliable public sold feed for them.

If a source only has a handful of sales, the item still shows, but lowSample is set and the page says so (Nintendo Switch 2 is $397.50 SOLD from only 6 sales, for example).

Weekly dated snapshots

The data refreshes once a week. Every snapshot is labeled with an ISO week ("week": "2026-W45") and an updated date, so you can store them and build your own history instead of trusting a number that silently changed.

3 ways to call it

curl, one item:

curl -s https://www.aiplannermail.com/api/v1/items/air-jordan-4-bred-reimagined.json 

JavaScript (browser or Node 18+):

const { items } = await (await fetch("https://www.aiplannermail.com/api/v1/items.json")).json(); console.table(items.map(i => ({ name: i.name, price: i.price, type: i.priceType, n: i.sampleSize }))); 

Python:

import requests items = requests.get("https://www.aiplannermail.com/api/v1/items.json").json()["items"] for i in items: print(f'{i["name"]}: ${i["price"]} {i["priceType"]} (n={i["sampleSize"]})') 

There is also a CSV for spreadsheets (=IMPORTDATA("https://www.aiplannermail.com/data/latest/items.csv") works in Google Sheets) and an OpenAPI spec at /api/openapi.json.

A few numbers from this week

Item Median Type Sample
Pokemon Prismatic Evolutions Elite Trainer Box $110 SOLD 17
Pokemon Delta Reign Elite Trainer Box $90 SOLD 25
Labubu Big Into Energy blind box $37 SOLD 45
Stanley Quencher 40oz $50 SOLD 24
Nintendo Switch 2 $397.50 SOLD 6 (low sample)

Limits

  • Weekly, not live. Good for trends and "is this a fair price", not for sniping.
  • Sample sizes are small for new or niche items; always read sampleSize.
  • Fee math uses each platform's published seller fees; shipping and promos vary.
  • License is CC BY 4.0: use it, cite it.

Docs and examples: aiplannermail.com/free-resale-price-api. Feedback on the schema, and which items to add, is very welcome in the comments.