Search 452,454 used sporting-goods listings by flex, curve, size and handedness - and read what gear actually sold for
SidelineSwap is the largest US peer-to-peer marketplace for used sporting goods, and this API reads it as JSON with no account and no key.
7 active endpoints, on 1, 2 and 3 credit tiers.
- POST/sidelineswap/v1/search
- POST/sidelineswap/v1/detail
- POST/sidelineswap/v1/comps
- POST/sidelineswap/v1/categories
- POST/sidelineswap/v1/filters
- POST/sidelineswap/v1/models
- POST/sidelineswap/v1/seller
What SidelineSwap endpoints does ReefAPI ship?
7 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
SidelineSwap API
9 of 7 endpoints, ready to run
Used right-handed hockey sticks over $50, cheapest first
// Press "Try it" and this pane shows exactly what the // live site returned this second — including an empty // result, if that is the truth. No key, no account.
How the SidelineSwap API works
SidelineSwap is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 438 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
From a sport to a priced, specification-matched used-gear feed
Find the category and the attribute ids SidelineSwap actually filters on, search with them, read what the gear sold for, then open the listings worth opening.
The sport and its 16 children with their ids. Deep categories only have ids, and this is where they come from - Hockey > Sticks is 110023.
The 13 attribute groups that category filters on, each value with its id: Flex (88 values), Pattern (64 curves), Stick Length (48), Hand, Age Group, Pro Stock, Is This Stick Cut, Stick Pack, Brand (65). Attributes belong to the exact category, so always call this on the one you will search.
The named models under that category and brand, with available and sold counts and a live price range. Take the model id for the comps call.
What that model actually sold for - min, p25, median, p75, max, mean over the newest 100 sold - next to the same statistics for the 253 currently listed, plus the sold-to-asked ratio.
The live listings matching the specification, with the source's own uncapped total, each row's state, condition, brand, price against retail, and the seller with their feedback score.
The whole listing: the seller's description, every attribute as its own field, parcel dimensions and weight, shipping and delivery estimate, all photos, offer settings, and the full seller block.
A dated feed of used gear you can actually compare: same model, same size or flex, same condition, with what equivalent items sold for next to what is being asked, and the seller's track record on every row.
curl -X POST https://api.reefapi.com/sidelineswap/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"category":"110023","detail":[76],"condition":["used"],"min_price":50,"sort":"price_asc","page_size":20}'{
"ok": true,
"data": { … },
"meta": {
"api": "sidelineswap",
"endpoint": "search",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}What a SidelineSwap field actually contains
Fields that read differently from how they look, and the limits worth knowing before you build on them. Every row was measured against live SidelineSwap responses on 2026-10-07 and 2026-10-08.
| Field | What it holds |
|---|---|
| total | SidelineSwap's own count for the query, and it is the real one. The site's own category pages print 50,000 with a truncation flag for anything large - three measurably different hockey queries all read "50000" on the web page - while this API answered 87,319 for the same sport and 452,454 unfiltered. total is the uncapped figure and it tracks every filter: against an unfiltered 19,268 hockey sticks in the same run, Used 6,274, New 12,994, left-handed 12,149, right-handed 7,137, pro stock 11,719, Bauer 4,781, CCM 6,896. |
| price_usd with state | One field, two meanings, and `state` is what tells them apart. On a live listing it is the asking price; on a sold listing it is the price the item ACTUALLY transacted at. That is why `state` is on every row and why `comps` exists. Checked against the price the item page itself publishes on 48 listings across six sports and both states: 48/48 exact. |
| state and the sold leak | `available` is the default, `sold` reads the sold side, `all` reads both, and the three are exactly additive: on hockey sticks available 19,245 + sold 149,405 = 168,650 for all. One caveat we publish rather than hide - the live feed keeps a just-sold listing for a short while, measured at 1 and 2 rows per 200 under the default order and 0 per 200 under `newest`. Each row's own `state` says which it is, and `sold_rows_in_available` counts them on every response. |
| attributes and attributes_flat | The gear columns, as the source publishes them per category, not parsed out of the title. `attributes` is the list with ids; `attributes_flat` is a `{slug: value}` map for quick reading - `{"hand": "Right", "hockey-stick-flex-individual": "70 Flex", "stick-pattern": ["P28", "Toe"], "age-group": "Senior", "condition": "New"}`. A group with two values comes back as a list, because a curve can be both a pattern family and a lie point. Filled on 12/12 detail calls across four sports. |
| detail (the parameter) and filters | Attribute ids are scoped to the exact category that carries them, and this is the one thing worth reading twice. A hockey-stick attribute such as Hand or Flex filters under Hockey > Sticks (110023) but NOT under Hockey (2000): the parent category does not carry those attributes, and asking anyway returns the unfiltered set. We refuse that combination with a message naming the id instead of returning an unfiltered result as a filtered one. Call `filters` on the category you are actually searching and use the ids it gives you. |
| condition | Two tiers only, the source's own: New and Used. There is no multi-grade ladder here - the wear detail lives in the seller's description and the photos. The two ids are global, verified identical across eight sports, so `condition` works the same everywhere. Measured on hockey sticks: Used 6,274 of 19,268, New 12,994. |
| age group | Reached through `detail` + `filters`, not as its own parameter, because the values differ per sport: hockey has Youth / Junior / Intermediate / Senior, baseball has Tee Ball (4-8) / Kid Pitch (9-13) / High School & College / Adult / Unknown, lacrosse has Adult / Youth. A single age-group enum would be wrong in most sports. |
| model | A model id groups every listing of one named product - `266943` is the Bauer Proto2 Hockey Stick, with 253 live and 912 sold. It is the sharpest input for `comps`. It cannot be combined with brand, condition, hand, pro_stock or detail: the source ignores all of them when a model is set (five filters, five identical responses), so we reject that combination rather than report a filter that did nothing. Price bounds, state and sort do still work with it. |
| comps statistics | The statistics describe the sample that was read, not the whole sold history, and both numbers are always returned side by side. Bauer Proto2 on 2026-10-08: total_sold 912, sold_sample_size 100, sold median $221.10, live median $245.00 over 253 available, median_sold_vs_available_pct 90.2. Sample up to 200 rows per call, newest first. |
| sold_via_offer | On a sold row, whether the sale went through an accepted offer rather than the listed price. Measured 50/50 filled on the sold surface with 23 of 50 true; it is null on live listings, where there is nothing to report yet. |
| retail_price_usd | The source's own retail reference, present on 23 of 100 live rows - not a majority, so treat it as a bonus rather than a baseline. `discount_vs_retail_pct` is computed from it and is null whenever it is missing. `list_price_usd` is filled 100/100 and tracks `price_usd`. |
| seller | The marketplace profile as the page shows it: username, profile link, badges and emblems (Pro Seller, Elite Seller, Quick Shipper, Verified Athlete, charity), feedback score with the positive/neutral/negative split, sales count, followers, the region and country they ship from, and their live/sold/draft counts. No name, street address, phone or e-mail - the source does not publish any of that on this surface and we do not go looking for it. |
| shipping | `feed_shipping_cost_usd` is the figure SidelineSwap publishes in its product feed and is filled on 12/12 detail calls. A real per-listing flat rate (`flat_rate_us_usd`) exists on only 1 of 48 listings, so do not build on it. `parcel` gives measured length, width, height and weight on 12/12, which is usually the more useful thing. |
| gtin, mpn | Sparse, not absent: 8 of 40 and 2 of 40 on new-condition golf and baseball listings, 0 of 12 on a mixed used sample. Most used gear simply has no barcode attached to it. The model-level gtin is effectively empty (1 of 750 models across three categories) and is returned only for completeness. |
| paging | total_pages is honest and the source does not repeat its last page - past the end it returns an empty page with has_more false (hockey-stick pages 963, 964 and 1000 all came back empty) rather than silently serving the last one again. page_size runs 1-200; 20 rows measured 29.6 KB and 1.4 s, 200 rows 285 KB and 2.3 s. Relevance order is reranked per request and is not reproducible between two identical calls - use `newest` or a price order when you need a stable page. |
| sort | Six orders, the site's own: relevance, newest, last_updated, trending, price_desc, price_asc. An unrecognised value is ignored upstream and silently returns relevance order over everything, so this is a closed list and anything else is refused with the list. |
Prices are USD. Sellers ship from the US (all regions) and Canada; `seller_location` filters on the source's own six regions. Measured across ~400 live calls on 2026-10-07 and 2026-10-08: no rate limiting and no blocked response at any point.
SidelineSwap coverage, measured
Every number below was read from live SidelineSwap responses on 2026-10-07 and 2026-10-08, two runs per endpoint, 24 of 24 calls in the final confirmation pass answered successfully.
452,454 live listings and 2,086,777 sold, across 36 listable sports and 806 category nodes. Live counts per sport: golf 107,432, hockey 87,319, baseball 73,072, apparel 56,226, footwear 42,512, lacrosse 21,776, skiing 21,548, softball 21,091, football 11,951, tennis and racket sports 11,051, snowboarding 9,575, soccer 8,207, memorabilia 7,205, inline and roller hockey 3,467, basketball 2,894, bikes 2,370, fitness 2,118, women's lacrosse 1,844, disc golf 1,630, wrestling 1,096, equestrian 682, motocross 416, fishing 255, paintball 74. Those sum to more than the total because a listing can sit in more than one category.
Published per category, not global. Hockey > Sticks returns 13 groups: Flex 88 values, Pattern 64, Stick Length 48, Brand 65, Age Group 4, Hand 2, Pro Stock 2, Is This Stick Cut 2, Stick Pack 5, Extension, Country of Manufacture 221. Skiing returns Boot Size, Gender and Age-Gender with Brand 196. Golf returns Hand and Gender with Brand 144. Baseball returns Colour 13 and Age Group 5 with Brand 67. Soccer returns Size. Condition is two tiers everywhere, New and Used.
The sold side keeps the transacted price and an accepted-offer flag, filled 50/50 on the sold surface with 23 of 50 true and null on live rows. Bauer Proto2 hockey stick on 2026-10-08: 912 sold, newest-100 sample median $221.10 (p25 $149.75, p75 $280.00, min $65, max $1,100), against 253 live with a median of $245.00 - a sold-to-asked ratio of 90.2 %. Hockey sticks overall: 19,245 live against 149,405 sold.
Against an unfiltered 19,268 hockey sticks in the same run: Used 6,274, New 12,994, left-handed 12,149, right-handed 7,137, pro stock 11,719, retail 2,920, P28 curve 4,006, 60-inch length 202, Senior 15,169, Bauer 4,781, CCM 6,896, over $400 2,036, under $50 837, price drops 977, shops 11,819, Canadian sellers 6,919, near ZIP 20146 1,075, sold 149,405, live and sold 168,673. All 20 move the count. Left plus right handed comes to 19,286 against a 19,268 control, so the two halves really do partition the set.
48 listings across six sports (hockey sticks, baseball, golf, lacrosse, skiing, football) and both states, each compared against the price, seller, condition and availability the item page itself publishes: 48/48 exact on price, 48/48 on seller, 48/48 on condition, 48/48 on availability - including SoldOut on 24 of 24 sold listings. Search to detail round-trip: 8/8 ids matched on id, price, name and seller.
On 100 search rows across four sports: id, name, state, price, list price, condition, sport, category, url, image, seller, favourites, views, listed and updated dates all 100/100; retail price and the discount computed from it 23/100. On 12 detail calls across four sports: attributes, brand, parcel, quantity, offers-accepted, shipping, photos, seller and condition 12/12; description 11/12; Google product category 11/12; model 10/12; retail price 4/12. Barcodes are sparse - gtin 8/40 and mpn 2/40 on new-condition golf and baseball.
Search 29.6 KB and 1.4 s at 20 rows a page, 285 KB and 2.3 s at 200. Detail 9.1 KB and 0.9 s. Comps 286 KB and 3.4 s. Filters 52.7 KB and 0.9 s. page_size runs 1-200. Paging is honest: hockey sticks give 962 pages of 20 and past the end the source returns an empty page rather than repeating the last one, so a loop terminates.
There is no confirmed sale date - sold rows carry updated_at, which is when the record last changed, and we do not relabel it. No buyer identity and no offer history, only the accepted-offer flag. A per-listing shipping price exists on 1 of 48 listings; the feed shipping cost and the measured parcel dimensions are published instead. Retail price is on 23 of 100 rows, not most. Barcodes are near-absent on used gear. The site's own category pages cap their totals at 50,000 while this API does not, so our counts will not match what the web page prints. Relevance order is reranked per request and is not reproducible between two identical calls - use newest or a price order for a stable page. A gear attribute filters only inside the exact category that carries it, so a stick's flex works under Hockey > Sticks and not under Hockey as a whole, and we refuse the second form rather than return an unfiltered result. The live feed keeps 1-2 just-sold rows per 200 under the default order. Nothing that needs an account is covered: watch-lists, messages, offers and checkout are out of scope.
What people build with SidelineSwap
The jobs this data is most often used for.
endpoints
credits per call
Price used gear before listing or buying it: pull `comps` for the exact model and read the sold median, quartiles and spread against what is currently being asked, instead of guessing from live listings alone.
Build a resale price index per sport, brand and model - 2,086,777 sold listings with transacted prices, model ids that group them, and available and sold counts on every model record.
Source inventory for a shop or reseller: filter by category, brand, condition, pro stock, price ceiling, price drops and seller region, sort by newest, and page through with the source's own honest totals.
Match gear to a player's specification rather than a search string: handedness, flex, curve pattern, stick length, age group, ski boot size or soccer size as real filters with the source's own ids.
What SidelineSwap data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 438 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/sidelineswap/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"category":"110023","detail":[76],"condition":["used"],"min_price":50,"sort":"price_asc","page_size":20}'import requests
r = requests.post(
"https://api.reefapi.com/sidelineswap/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"category": "110023",
"detail": [
76
],
"condition": [
"used"
],
"min_price": 50,
"sort": "price_asc",
"page_size": 20
},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up SidelineSwap.
Get a free key →Do I need a SidelineSwap account or key?▾
No. Everything this API reads is the public marketplace: search, listings, the category and attribute taxonomies, model catalogues and public seller profiles. Nothing behind a login is touched, so there are no credentials to manage and nothing to keep warm.
Can I get the price gear actually sold for, not just asking prices?▾
Yes, and that is the main reason to use this one. SidelineSwap keeps 2,086,777 sold listings with the price each transacted at, and `comps` turns them into min, p25, median, p75, max and mean for a model or category, next to the same statistics for what is currently listed. Bauer Proto2 hockey sticks on 2026-10-08: 912 sold, sample median $221.10, against a live median of $245.00 over 253 available - a sold-to-asked ratio of 90.2 %. Each sold row also says whether the sale went through an accepted offer.
How do I filter by hockey-stick flex, curve or handedness?▾
Call `filters` on the category you are searching - for Hockey > Sticks (id 110023) it returns 13 attribute groups including Flex with 88 values, Pattern with 64 curves, Stick Length with 48, Hand, Is This Stick Cut, Stick Pack and Age Group - then pass the ids you want to `search` as `detail`. Handedness and condition also have plain named parameters (`hand`, `condition`) because their ids are the same in every sport. One thing to know: attributes belong to the exact category that carries them, so a stick attribute filters under Hockey > Sticks and not under Hockey as a whole.
Which sports and how much of each?▾
36 listable sports, 806 category nodes. Measured live counts on 2026-10-08: golf 107,432, hockey 87,319, baseball 73,072, apparel 56,226, footwear 42,512, lacrosse 21,776, skiing 21,548, softball 21,091, football 11,951, tennis and racket sports 11,051, snowboarding 9,575, soccer 8,207, memorabilia 7,205, inline and roller hockey 3,467, basketball 2,894, bikes 2,370, fitness 2,118, women's lacrosse 1,844, disc golf 1,630, wrestling 1,096, equestrian 682, motocross 416, fishing 255, paintball 74, plus smaller ones. Those add up to more than the 452,454 total because a listing can sit in more than one category.
Is pro-stock gear separated from retail?▾
Yes, it is a real split on this source and a filter of its own. Pro stock means team-issued equipment that was never a retail SKU, and 11,719 of 19,268 hockey sticks are flagged as it against 2,920 flagged retail. `pro_stock` takes `pro_stock` or `retail`.
Can I follow one seller, or find gear near me?▾
Both. `search` takes a `seller` username for everything one seller has listed, and `seller` returns their public profile - badges, feedback split, sales count, ships-from region and live/sold counts - with their current listings and, optionally, the feedback buyers left. For location, `near_zip` takes a 5-digit US ZIP and narrows to sellers near it (20146 cut 452,454 to 66,402), and `seller_location` filters on the source's own regions, including Canada.
How fresh is the data, and are sold items mixed into live results?▾
Every call reads SidelineSwap live - there is no cached copy behind this API. Listings carry their own `listed_at` and `updated_at`. Sold items are a separate mode (`state`), but the live feed does keep a just-sold listing for a short while: measured at 1 and 2 rows per 200 under the default order and 0 per 200 under `newest`. Every row carries its own `state` and each response counts the overlap, so you can drop them or keep them deliberately.
What does this API not give me?▾
A confirmed sale date - sold rows carry `updated_at`, which is when the record last changed, and we do not relabel it as a sale timestamp. No buyer identity and no offer history, only the accepted-offer flag. No seller name, address, phone or e-mail, because the public surface has none. A per-listing shipping price exists on about 1 in 48 listings; the feed shipping cost and the measured parcel dimensions are there instead. Barcodes are sparse - 8 of 40 on new-condition gear, near zero on used. And nothing that needs an account: watch-lists, messages, offers and checkout are all out of scope.
What is the SidelineSwap API?▾
SidelineSwap API is a ReefAPI endpoint group for used sporting goods across 36 us sports: listings with brand, model, condition, size, flex, curve and handedness as their own fields, plus the prices gear actually sold for. It returns live JSON through POST requests under /sidelineswap/v1.
Is the SidelineSwap API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. SidelineSwap calls use the same shared credit balance as every other ReefAPI engine.
Do I need a SidelineSwap login or account?▾
No login to SidelineSwap is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the SidelineSwap data?▾
The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the SidelineSwap API use?▾
SidelineSwap actions currently cost 1-3 credits per successful call. Failed or blocked calls are free. All APIs draw from one credit pool.
Can I call SidelineSwap from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call sidelineswap actions with the same key, credit pool and JSON envelope used by normal REST requests.
191 E-commerce & Marketplaces APIs on the same key
One key, one credit pool, one response envelope. If you are pulling SidelineSwap, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 437 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-10-07.