# SidelineSwap — used sporting goods marketplace (US)

> Search SidelineSwap's used and new sporting-goods listings across 36 sports (450,265 live listings measured 2026-10-07), or the 2,086,728 SOLD listings with the price they actually transacted at. Filter by sport or category, brand, model, condition, handedness, pro-stock vs retail, price, seller type, seller region, US ZIP proximity and the source's own category-specific attributes (hockey-stick flex, curve pattern, stick length, ski boot size, soccer size…). Needs no account and no key. Pass at least one of query, category, model or seller unless you really want the whole catalogue.
> ReefAPI engine `sidelineswap` · 7 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/sidelineswap/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/sidelineswap/v1/search — 2 credits
Search SidelineSwap's used and new sporting-goods listings across 36 sports (450,265 live listings measured 2026-10-07), or the 2,086,728 SOLD listings with the price they actually transacted at. Filter by sport or category, brand, model, condition, handedness, pro-stock vs retail, price, seller type, seller region, US ZIP proximity and the source's own category-specific attributes (hockey-stick flex, curve pattern, stick length, ski boot size, soccer size…). Needs no account and no key. Pass at least one of query, category, model or seller unless you really want the whole catalogue.

**Parameters:**
- `query` (string, optional) — Free-text search over listing titles. The source's own key is `q`; `query`, `keywords`, `search` and `term` are silently DROPPED upstream (measured: 450,268 rows instead of 20,711), so this engine always sends the one that works.
- `category` (string, optional) — Sport or category. Either a top-level sport slug — apparel, athlete-bundles, baseball, basketball, bikes, bowling, disc-golf, electronics-gaming-esports, equestrian, fencing, field-hockey-category, figure-skating, fishing, fitness, fitness-trackers-wearables, football, footwear, golf, hike-camp, hockey, inline-roller, lacrosse, memorabilia, motocross, other-others, paintball, skateboarding, skiing, snowboarding, snowshoe, soccer, softball, surf-wake-water, tennis-racquet-sports, womens-lacrosse, wrestling — or a numeric category id from the categories action (deeper categories such as hockey Sticks = 110023 only have an id). A numeric id is checked against the source's own taxonomy first, because sidelineswap answers HTTP 200 and THE WHOLE CATALOGUE for an id it does not know.
- `detail` (array, optional) — Category-specific attribute ids, from the filters action — this is where the vertical values live: hockey-stick Flex, Pattern/curve, Stick Length, Is This Stick Cut, Stick Pack, Age Group, ski Boot Size, soccer Size, golf Gender, Country of Manufacture. Repeatable. Requires category, because the ids are scoped to a category and every id is validated against that category's own taxonomy before the search is sent. Age group is here rather than as its own parameter because its ids differ per sport (hockey Senior 23077, baseball Adult 23076, baseball Tee Ball 24029).
- `condition` (array, optional) — The source's own two condition tiers. Global ids, verified identical across 8 sports (New 31 / Used 17). [one of: new, used]
- `hand` (array, optional) — Handedness, for the categories that carry it (hockey sticks, golf clubs, baseball/softball gloves). Measured to bite: 12,137 left vs 7,119 right of 19,238 hockey sticks, and 6/6 returned rows carried Hand=Right in their own attribute block. [one of: left, right]
- `pro_stock` (array, optional) — Pro-stock vs retail. This is a real market split on this source: 22,148 of 86,649 hockey listings are pro stock. [one of: pro_stock, retail]
- `brand` (array, optional) — Brand ids from the filters action (hockey: Bauer 68, CCM 69, Warrior 2). Repeatable. Note the source uses `brand` here and `brand_id` on the models action — the engine sends each the name that one accepts.
- `model` (integer, optional) — A model id from the models action, e.g. 266943 = Bauer Proto2 Hockey Stick. CANNOT be combined with brand, detail, condition, hand or pro_stock: the source silently ignores all of them when model is set, so the engine rejects that combination instead of reporting a filter that did nothing. min_price, max_price, state and sort do still work with it.
- `min_price` (number, optional) — Lowest asking price in USD, inclusive.
- `max_price` (number, optional) — Highest asking price in USD, inclusive.
- `state` (enum, optional, default "available") — Which side of the market to read. The three modes are exactly additive, measured on hockey sticks: available 19,245 + sold 149,405 = all 168,650. [one of: available, sold, all]
- `item_type` (array, optional) — Listing-type flags the source itself facets on. Measured inside hockey: price_drop 6,441 of 86,649; us_free_shipping 872; auction 17. [one of: accepts_offers, auction, canada_free_shipping, expedited_shipping, price_drop, recently_sold, us_free_shipping]
- `seller_option` (array, optional) — Seller-type flags. Measured inside hockey: shop (business) 41,498; pro_seller 31,546; locker (individual) 45,150; charity 903. [one of: charity, curated, elite, fast_shipper, locker, pro_seller, pro_stock_reseller, shop, sidelineswap_athlete, verified_athlete]
- `seller_location` (array, optional) — Where the seller ships from. Measured inside hockey: canada 18,372; us_midwest 23,727; us_northeast 21,673. [one of: canada, us, us_midwest, us_northeast, us_south, us_west]
- `superlative` (array, optional) — The source's own editorial picks. Measured inside hockey: rare_find 4,294; best_seller 4,462; new_release 14. [one of: rare_find, best_seller, new_release]
- `seller` (string, optional) — One seller's listings, by marketplace USERNAME (a numeric value returns 0 rows upstream and is refused here).
- `near_zip` (string, optional) — 5-digit US ZIP code; the source re-ranks and narrows to sellers near it (measured: 66,402 of 450,265 for 20146).
- `sort` (enum, optional, default "relevance") — The source's own six orders. An unknown value is silently ignored upstream (relevance order, full catalogue), so this is a closed list. Relevance order is NOT stable between calls — use newest or a price order when you need a repeatable page. [one of: relevance, newest, last_updated, trending, price_desc, price_asc]
- `page` (integer, optional, default 1) — 1-based page. Past the last page the source answers an EMPTY page with has_more=false — it does not repeat the last page (measured: hockey-stick pages 963, 964 and 1000 all came back empty and byte-identical).
- `page_size` (integer, optional, default 20) — Rows per page, 1-200 (the source's own default is 20; 20 rows measured 28.7 KB / 1.2 s, 200 rows 285 KB / 2.3 s).
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {query, total, page, page_size, last_page, has_more, state, sort, filters_applied{}, sold_rows_in_available, items[{id, name, state, price_usd, list_price_usd, retail_price_usd, discount_vs_retail_pct, condition{id,slug,name}, sport, category_slug, url, image{}, seller{id,username,url,emblems,badges,feedback_score,feedback_count,avatar_url}, favorites, views, label, sold_via_offer, listed_at, updated_at}]}

**Example request body:**
```json
{
  "category": "110023",
  "detail": [
    76
  ],
  "condition": [
    "used"
  ],
  "min_price": 50,
  "sort": "price_asc",
  "page_size": 20
}
```

### POST https://api.reefapi.com/sidelineswap/v1/detail — 1 credit
One listing in full, as the item page publishes it: the seller's own description, every category-specific attribute as its OWN field (flex, pattern, hand, stick length, age group, boot size…), condition tier, asking price against retail price, parcel dimensions and weight, shipping and delivery estimate, all photos, offer and auto-price-drop settings, and the full seller block with badges and feedback totals. Works for sold listings too, where `price_usd` is the transacted price and `sold_via_offer` says whether it went through an accepted offer.

**Parameters:**
- `id` (string, required) — Listing id, or the full sidelineswap.com listing URL (the id is the number at the start of the last path segment). Works for sold listings too, where price_usd is the price it transacted at.
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {item{id, uuid, name, state, description, price_usd, list_price_usd, retail_price_usd, discount_vs_retail_pct, condition{}, attributes[{slug,name,values[{id,slug,name}]}], attributes_flat{}, sport, category_slug, categories[], brand, model{id,name,display_name,gtin,mpn,url}, gtin, mpn, quantity, accepts_offers, sold_via_offer, auto_price_drop, auto_price_drop_min_usd, bundle, superlative_label, favorites, interested_count, views, google_product_category, shipping{}, parcel{}, buyer_protection_available, actions[], images[], seller{}, url, listed_at, updated_at, noindex}}

**Example request body:**
```json
{
  "id": "12755098"
}
```

### POST https://api.reefapi.com/sidelineswap/v1/comps — 3 credits
Sold-price comparables: what gear of this kind ACTUALLY sold for on SidelineSwap, not what it is being asked for. Reads the source's sold side (2,086,728 sold listings) for one model, category or search term and returns min / p25 / median / p75 / max / mean over the sample plus the live-side statistics for the same query, so an asking price can be read against the transacted ones. Each sold row keeps its own price, condition, date and whether the sale went through an accepted offer. Pass at least one of model, category or query.

**Parameters:**
- `model` (integer, optional) — A model id from the models action — the sharpest comparable set, e.g. 266943 = Bauer Proto2 Hockey Stick (912 sold, 252 live).
- `category` (string, optional) — Sport or category. Either a top-level sport slug — apparel, athlete-bundles, baseball, basketball, bikes, bowling, disc-golf, electronics-gaming-esports, equestrian, fencing, field-hockey-category, figure-skating, fishing, fitness, fitness-trackers-wearables, football, footwear, golf, hike-camp, hockey, inline-roller, lacrosse, memorabilia, motocross, other-others, paintball, skateboarding, skiing, snowboarding, snowshoe, soccer, softball, surf-wake-water, tennis-racquet-sports, womens-lacrosse, wrestling — or a numeric category id from the categories action (deeper categories such as hockey Sticks = 110023 only have an id). A numeric id is checked against the source's own taxonomy first, because sidelineswap answers HTTP 200 and THE WHOLE CATALOGUE for an id it does not know.
- `query` (string, optional) — Free-text narrowing, same key as search.
- `detail` (array, optional) — Category-specific attribute ids, from the filters action — this is where the vertical values live: hockey-stick Flex, Pattern/curve, Stick Length, Is This Stick Cut, Stick Pack, Age Group, ski Boot Size, soccer Size, golf Gender, Country of Manufacture. Repeatable. Requires category, because the ids are scoped to a category and every id is validated against that category's own taxonomy before the search is sent. Age group is here rather than as its own parameter because its ids differ per sport (hockey Senior 23077, baseball Adult 23076, baseball Tee Ball 24029). Not available together with model.
- `brand` (array, optional) — Brand ids from the filters action. Not available together with model.
- `condition` (array, optional) — Condition tier. Not available together with model. [one of: new, used]
- `sample_size` (integer, optional, default 100) — How many sold listings to read for the statistics, 1-200. The statistics describe THIS SAMPLE; `total_sold` is the source's full count and is usually much larger, so sold_sample_size is always reported next to it.
- `min_price` (number, optional) — Drop sold rows below this USD price before computing statistics.
- `max_price` (number, optional) — Drop sold rows above this USD price before computing statistics.
- `include_rows` (boolean, optional, default true) — Return the individual sold listings alongside the statistics.
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {filters_applied{}, total_sold, sold_sample_size, sold_price_stats{count,min_usd,p25_usd,median_usd,p75_usd,max_usd,mean_usd}, total_available, available_sample_size, available_price_stats{}, median_sold_vs_available_pct, sold_items[], available_items[]}

**Example request body:**
```json
{
  "model": 266943,
  "sample_size": 60
}
```

### POST https://api.reefapi.com/sidelineswap/v1/categories — 1 credit
SidelineSwap's own category tree: 36 listable top-level sports and 806 nodes in all. This is where the numeric category ids that search, comps, filters and models take come from. Call it with no parameters for the sports, or with a sport to walk into it (hockey has 16 children).

**Parameters:**
- `category` (string, optional) — Limit the tree to one sport slug or category id. Omit it for all 36 sports.
- `depth` (integer, optional, default 1) — How many levels of children to include. 0 = the nodes themselves, 1 = one level of children (the default), 4 = the whole subtree.
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {count, categories[{id, slug, name, full_name, listable, child_count, url, children[…]}]}

**Example request body:**
```json
{
  "category": "hockey",
  "depth": 1
}
```

### POST https://api.reefapi.com/sidelineswap/v1/filters — 1 credit
The attribute taxonomy SidelineSwap itself uses for one category — the lookup table behind the `detail` parameter of search and comps. For hockey sticks it returns 13 groups including Flex (88 values), Pattern (64 curves), Stick Length (48), Hand, Age Group, Pro Stock, Is This Stick Cut, Stick Pack and Brand (65); for skiing it returns Boot Size; for soccer, Size. Each value carries the id to pass back. Which groups exist depends on the category, which is why this is a per-category lookup and not one global list.

**Parameters:**
- `category` (string, required) — Sport or category. Either a top-level sport slug — apparel, athlete-bundles, baseball, basketball, bikes, bowling, disc-golf, electronics-gaming-esports, equestrian, fencing, field-hockey-category, figure-skating, fishing, fitness, fitness-trackers-wearables, football, footwear, golf, hike-camp, hockey, inline-roller, lacrosse, memorabilia, motocross, other-others, paintball, skateboarding, skiing, snowboarding, snowshoe, soccer, softball, surf-wake-water, tennis-racquet-sports, womens-lacrosse, wrestling — or a numeric category id from the categories action (deeper categories such as hockey Sticks = 110023 only have an id). A numeric id is checked against the source's own taxonomy first, because sidelineswap answers HTTP 200 and THE WHOLE CATALOGUE for an id it does not know.
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {category_id, count, groups[{slug, name, required, value_count, values[{id, slug, name}]}]}

**Example request body:**
```json
{
  "category": "110023"
}
```

### POST https://api.reefapi.com/sidelineswap/v1/models — 2 credits
The model catalogue for a category: the named products SidelineSwap groups listings under, with the brand, the source's own GTIN/MPN where it has them, how many are available and how many have sold, and the model's live price range. This is where the `model` id for search and comps comes from. Note the source wants `brand_id` on this endpoint while search wants `brand` — the engine sends each the name that one actually accepts; `brand` here is ignored upstream and would quietly return every brand's models.

**Parameters:**
- `category` (string, required) — Sport or category. Either a top-level sport slug — apparel, athlete-bundles, baseball, basketball, bikes, bowling, disc-golf, electronics-gaming-esports, equestrian, fencing, field-hockey-category, figure-skating, fishing, fitness, fitness-trackers-wearables, football, footwear, golf, hike-camp, hockey, inline-roller, lacrosse, memorabilia, motocross, other-others, paintball, skateboarding, skiing, snowboarding, snowshoe, soccer, softball, surf-wake-water, tennis-racquet-sports, womens-lacrosse, wrestling — or a numeric category id from the categories action (deeper categories such as hockey Sticks = 110023 only have an id). A numeric id is checked against the source's own taxonomy first, because sidelineswap answers HTTP 200 and THE WHOLE CATALOGUE for an id it does not know.
- `brand` (integer, optional) — One brand id from the filters action (hockey: Bauer 68, CCM 69). Measured: narrows hockey-stick models from 250 across many brands to 196 Bauer models.
- `query` (string, optional) — Free-text narrowing on the model name (measured: 'proto' inside hockey sticks → 3 models, 4.8 KB instead of 355 KB).
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {category_id, count, models[{id, name, display_name, brand, brand_id, category, category_id, gtin, mpn, available_count, sold_count, price_min_usd, price_max_usd, expert_pick, popular, description, url}]}

**Example request body:**
```json
{
  "category": "110023",
  "brand": 68,
  "query": "proto"
}
```

### POST https://api.reefapi.com/sidelineswap/v1/seller — 2 credits
A seller's public marketplace profile: username, badges and emblems, feedback score with the positive/neutral/negative split, sales and follower counts, the region and country they ship from, and their live/sold/draft listing counts. Optionally their current listings and their received feedback comments. Public profile data only — the source publishes no name, street address, phone or e-mail on this surface and this engine does not go looking for any.

**Parameters:**
- `username` (string, required) — Marketplace username, or the numeric user id, or the profile URL.
- `include_items` (boolean, optional, default true) — Also return the seller's current live listings.
- `include_feedback` (boolean, optional, default false) — Also return the feedback comments buyers left, with rating and date.
- `page_size` (integer, optional, default 20) — Rows per page, 1-200 (the source's own default is 20; 20 rows measured 28.7 KB / 1.2 s, 200 rows 285 KB / 2.3 s).
- `include_pii` (boolean, optional, default false) — Kept for contract compatibility. It changes nothing here: sidelineswap publishes a marketplace username, region and badge/feedback totals and no personal contact detail, so there is nothing to hold back.

**Returns:** {seller{id, uuid, username, url, avatar_url, cover_url, emblems, badges, feedback{score,count,count_positive,count_neutral,count_negative}, feedback_avg, sales_count, follower_count, following_count, ships_from_country, ships_from_region, item_count{available,sold,draft,removed}, power_seller, ambassador, indexable, on_vacation}, items[], feedback_comments[]}

**Example request body:**
```json
{
  "username": "WestProStock",
  "include_items": true
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

## More
- Try it live, no code: https://reefapi.com/playground?engine=sidelineswap
- Human docs page: https://reefapi.com/docs/sidelineswap
- Overview page: https://reefapi.com/sidelineswap-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
