buycycle API & Scraper
buycycle is a European marketplace for pre-owned bikes, bike parts, cycling gear, running, winter-sports and outdoor equipment, and this API reads it as JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
On 2026-10-08 it carried 125,567 live listings: 53,759 bikes, 48,134 cycling-gear items, 15,245 running, 6,628 winter-sports, plus outdoor, ball, water and racket sports. `search` takes free text plus buycycle's own filters - department, discipline, leaf category, brand, model family, frame/wheel/clothing/shoe size, frame material, brake type, shifting type, colour, condition, private or commercial seller, the country the item is physically in, price, model year, e-bike, frameset and high-demand - sorted by relevance, newest, oldest or price, up to 200 rows a page. The bike-specific values come back as their own fields, not as text inside the title: brand, model year, frame size in centimetres, size letter, groupset, condition and discipline on every search row; frame material, brake type, shifting type, suspension type, wheel size, colour, recommended rider height and the full component list on `detail`. `detail` also returns the asking price, the total including buyer protection, the shipping cost and destination, the return window, the MSRP, the seller's own description with buycycle's translation of it, every image, the city and country the item sits in, the seller with their rating, and buycycle's own market-price verdict on the asking price. `seller` returns a profile - private or commercial, country, city, rating, reviews, items for sale, items sold, followers, member-since - with their live listings. `filters` returns every filter value with its live count, and `markets` the 28 storefronts with their currencies.
What a buycycle field actually contains
Fields that read differently from how they look. Every row was measured against live buycycle responses on 2026-10-08.
| Field | What it holds |
|---|---|
| total | buycycle's own filter-aware count, and it is the real one. The raw counter the search index returns stops at 10,000 no matter how many matches there are; total is read from the count the index keeps per result set, which agrees to the item with the site's own shop page (125,653 on the page, the same figure from the API in the same minute) and with narrow queries where nothing is capped (Specialized 5,851, Canyon 2,326, Specialized or Canyon 8,177). total_capped tells you the raw counter was at its ceiling, which never changes total. |
| last_page, result_window | buycycle serves the first 10,000 rows of any result, whatever the total. At 52 rows a page the last page with rows is 193 and it holds exactly 16; at 200 rows a page it is 50. Asking past that is rejected with the number, not answered with an empty page. Narrow with filters to reach deeper. |
| frame_size vs size | Two different vocabularies, both as the listing prints them. frame_size is the bike measurement ("54 cm", "MD", "L") and arrives on 50 of 50 bike rows and none of the gear rows. size is the letter or number vocabulary used by clothing, shoes and helmets. The size FILTER takes one list covering all of them: frame sizes xxxs to xxl, wheel sizes 26 / 27-5-650b / 28-700c / 29, clothing clothing-size-s to 3xl, shoes eu-42 / eu-42-5, helmets helmet-size-m. filters returns the live list grouped per vocabulary. |
| condition | Four grades the filter accepts - NEW (40,917 listings), VERY_GOOD (54,056), GOOD (28,598), FAIR (1,988) - plus a fifth, NEW_WITH_WARRANTY, that buycycle stamps on some shop listings and its own filter cannot select. condition_label is the wording the page shows. The grades are not numbered in quality order upstream, so read the names, not an index. |
| price and currency | price is in the currency of the storefront you asked for, and currency says which. The same bike reads 2,730 EUR on the German storefront and 69,291 CZK on the Czech one; listing_currency keeps the currency the seller listed in. total_with_buyer_protection is the same bike with buycycle's buyer-protection fee added (2,730 becomes 2,799), and shipping_cost is quoted separately. |
| msrp, msrp_shown | The recommended retail price, when buycycle shows one - 42 of 50 bike rows. It arrives as 0 rather than empty on listings with none, and a few listings carry an MSRP below the asking price, so read msrp_shown before you compute a discount from it. |
| is_price_reduced | buycycle's own flag that the asking price came down. It does not publish what it came down FROM: on every listing we checked that carried the flag, the source's "original" price was the same number as the current one. We do not invent the old figure. |
| groupset | The drivetrain as buycycle names it - "Shimano Ultegra Di2", "SRAM Force eTap AXS", "Sram Eagle Transmission GX". On 50 of 50 bike rows, and on no gear rows. |
| seller | A display name as buycycle shows it ("Alban M."), the numeric seller id, the profile link, the star rating, the review count and when they were last active. 94,955 of the 125,567 listings are from private people and 30,638 from commercial shops; seller_type filters either way. No e-mail, phone or surname - buycycle does not publish them. |
| country vs market | Two different things. country filters by where the item physically is (Germany 24,877 listings, France 20,013) and every row carries country_code. market picks which of the 28 buycycle storefronts to read, which sets the currency and the page language. The catalogue is pan-European and identical in every storefront. |
| sort | relevance is buycycle's reranked default and it is not reproducible - two identical calls a second apart returned different first rows. newest, oldest, price_asc and price_desc are stable, and newest really is newest (top rows timestamped minutes before the call). |
| total moves while you read it | buycycle is live: the unfiltered total read 125,555, 125,567 and 125,653 in three calls within the same hour, and the newest listings in a newest-first page were timestamped minutes before the call. Treat any count here as a reading with a timestamp, not a constant. |
| description | What the seller wrote, on 47 of 50 bike rows, plus buycycle's own translation of it on detail (a French listing came back with an English version alongside). description_tags are the badges buycycle derives from that text - "Recently serviced", "Low mileage", "New chain". |
Kilometres ridden is NOT a field buycycle publishes - it only ever appears inside a seller's free text and as a "Low mileage" badge, so we do not fake it. Sold and withdrawn listings leave every buycycle surface: those return NOT_FOUND, not a stale record.
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/buycycle/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "specialized tarmac",
"condition": [
"VERY_GOOD"
],
"frame_material": [
"carbon"
],
"sort": "price_desc"
}
}{
"ok": true,
"meta": {
"api": "buycycle",
"endpoint": "search",
"mode": "live",
"latency_ms": 995.4,
"record_count": 52,
"bytes": 103131,
"cache_hit": false,
"upstream_requests": 1,
"charged_credits": 2,
"version": "1.0.0",
"request_id": "658fdcb4b73e4b66",
"queue_ms": 2.3,
"fetched_at": "2026-10-08T11:33:19.065Z"
},
"data": {
"query": "specialized tarmac",
"total": 799,
"total_capped": false,
"page": 1,
"page_size": 52,
"last_page": 16,
"has_more": true,
"result_window": 10000,
"sort": "price_desc",
"filters_applied": {
"frame_material": [
"carbon"
],
"condition": [
"3"
]
},
"products": [
{
"id": 1848373,
"title": "S-Works Tarmac SL8 - Forward 50 LTD 2025",
"url": "https://buycycle.com/product/s-works-tarmac-sl8-forward-50-ltd-2025-56951",
"slug": "s-works-tarmac-sl8-forward-50-ltd-2025-56951",
"product_type": "bike",
"main_type": "bike",
"brand": "Specialized",
"category": "Roadbike",
"discipline": "Road & Gravel",
"year": 2025,
"frame_size": "52 cm",
"size": "S",
"groupset": "Shimano Dura Ace Di2",
"description": "custom painted frame",
"condition": "VERY_GOOD",
"condition_label": "Very good",
"price": 17000,
"currency": "EUR",
"msrp": 16500,
"msrp_shown": false,
"is_price_reduced": false,
"is_high_demand": false,
"favorite_count": 8,
"buyer_offers": 0,
"country_id": 136,
"country_code": "si",
"seller_id": 79981,
"listed_at": "2026-02-07T15:47:46Z",
"listed_at_ts": 1770479266,
"updated_at": "2026-03-21T16:24:09Z",
"image": "https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2358234/a133516d-0140-43fa-b186-0341ed71a254.webp",
"images": [
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2358234/a133516d-0140-43fa-b186-0341ed71a254.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2358234/f51fc267-1230-4a41-b270-1e73dc1d922c.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2358234/b99d7358-e221-43de-8be4-41ece9ec9edc.webp"
],
"images_count": 4
},
{
"id": 2045657,
"title": "S-Works Tarmac SL8 LTD: Red Bull - BORA - hansgrohe Edition 2025",
"url": "https://buycycle.com/product/s-works-tarmac-sl8-ltd-red-bull-bora-hansgrohe-edition-2025-77602",
"slug": "s-works-tarmac-sl8-ltd-red-bull-bora-hansgrohe-edition-2025-77602",
"product_type": "bike",
"main_type": "bike",
"brand": "Specialized",
"category": "Roadbike",
"discipline": "Road & Gravel",
"year": 2025,
"frame_size": "49 cm",
"size": "XS",
"groupset": "SRAM Red eTap AXS",
"description": "Official bike purchased from Specialized, limited and numbered edition 348/500, delivered by Specialized and the Red Bull team in 2025 in Lisbon at the start of “La Vuelta a España 2025”. Invoice and photographs available. All original components except for the CeramicSpeed aloja team pulley wheel, original zero-offset seatpost.\n\nDelivered without pedals or bottle cages.\n\nSize 49.\n\nIt is a luxury item; I also have another one in size 54 for sale.",
"condition": "VERY_GOOD",
"condition_label": "Very good",
"price": 12300,
"currency": "EUR",
"msrp": 16500,
"msrp_shown": true,
"is_price_reduced": true,
"is_high_demand": false,
"favorite_count": 27,
"buyer_offers": 0,
"country_id": 156,
"country_code": "es",
"seller_id": 4690902,
"listed_at": "2026-04-11T15:54:10Z",
"listed_at_ts": 1775922850,
"updated_at": "2026-09-26T12:56:44Z",
"image": "https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491619/c24f7afb-ed7b-43e9-8c79-c382920381bf.webp",
"images": [
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491619/c24f7afb-ed7b-43e9-8c79-c382920381bf.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491619/87db76a5-3711-44fd-bf8e-745934755748.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491619/42ddc3cd-6cb1-4386-983b-7c4d9cb1f1e2.webp"
],
"images_count": 4
},
{
"id": 2045613,
"title": "S-Works Tarmac SL8 LTD: Red Bull - BORA - hansgrohe Edition 2025",
"url": "https://buycycle.com/product/s-works-tarmac-sl8-ltd-red-bull-bora-hansgrohe-edition-2025-30237",
"slug": "s-works-tarmac-sl8-ltd-red-bull-bora-hansgrohe-edition-2025-30237",
"product_type": "bike",
"main_type": "bike",
"brand": "Specialized",
"category": "Roadbike",
"discipline": "Road & Gravel",
"year": 2025,
"frame_size": "54 cm",
"size": "M",
"groupset": "SRAM Red eTap AXS",
"description": "Official bike purchased from Specialized, limited and numbered edition 192/500, delivered by Specialized and the Red Bull team in 2025 in Lisbon at the start of \"La Vuelta a España 2025\". We have the invoice and photographs. All components are original except for the CeramicSpeed Alpha Team pulley wheel. Original seatpost with 1.5mm setback.\n\nSold without pedals or bottle cages.\n\nSize 54.\n\nThere is a mark on the lower part of the left side of the fork due to transport on a bike rack; photo provided.\n\nOn 06-07-2026, there is a scratch on the right shifter resulting from a stationary fall; photo",
"condition": "VERY_GOOD",
"condition_label": "Very good",
"price": 12300,
"currency": "EUR",
"msrp": 16500,
"msrp_shown": true,
"is_price_reduced": true,
"is_high_demand": false,
"favorite_count": 52,
"buyer_offers": 0,
"country_id": 156,
"country_code": "es",
"seller_id": 4690902,
"listed_at": "2026-04-11T15:36:09Z",
"listed_at_ts": 1775921769,
"updated_at": "2026-09-26T12:56:26Z",
"image": "https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491592/d7b28768-9504-4e4e-a1dc-746ebc76b378.webp",
"images": [
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491592/d7b28768-9504-4e4e-a1dc-746ebc76b378.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491592/b252aebd-b2d8-47a8-a505-cc0fe7ff97b6.webp",
"https://d1mgeijqpfaspl.cloudfront.net/uploads/bike/media/2491592/a9cb5b94-ee7f-4917-bda6-d30169001d36.webp"
],
"images_count": 4
}
]
}
}What the buycycle API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | Search buycycle, Europe's largest marketplace for pre-owned bikes and sports gear: ~125,000 live listings from private sellers and shops across 28 storefront countries. Free text plus the site's own filters — department, discipline, category, brand, model family, frame/wheel/clothing/shoe size, frame material, brake type, shifting type, colour, condition, seller type, the country the item is in, price, model year, e-bike, frameset and high-demand — and its four working sort orders. Nothing is required: with no parameters it browses the live catalogue. Bike-specific values (frame size, model year, groupset, frameset flag, discipline) come back as their own fields, not buried in the title. | Pricing teams call search to search buycycle, Europe's largest marketplace for pre-owned bikes and sports gear. | query, main_type, discipline, category, brand, ... |
| detail | One buycycle listing in full, exactly what the product page publishes: title, brand, model, year, condition with the site's own grading note, asking price, the original price, the total including buyer protection, shipping cost and destination, return window, MSRP, frame size with the recommended rider height, frame material, brake and shifting type, suspension, wheel size, colour, groupset, every component the seller listed (original and replaced), the seller's own description and buycycle's translation of it, every image, the city and country the item is in, the seller (name, rating, reviews, profile) and buycycle's own market-price rating for the asking price. | Marketplace operators call detail to get one buycycle listing in full, exactly what the product page publishes. | id, market, language, include_pii |
| seller | A buycycle seller's public profile and the listings on it: private or commercial, country and city, star rating, review count, items for sale, items sold, followers, member-since, verification and top-seller badges, plus the first page of their live listings with prices and condition. | Catalog enrichment teams call seller to get a buycycle seller's public profile and the listings on it. | seller_id, market, language, include_pii |
| filters | Every filter value buycycle currently offers, with the live count behind each one: departments, disciplines, categories, brands, model families, sizes per vocabulary, frame materials, brake and shifting types, groupsets, colours, conditions, seller types, e-bike/frameset flags and the price and year ranges. Use it to discover the exact slugs `search` filters on, and as a market-size report in its own right (how many carbon road bikes, how many Canyons). | Retail analysts call filters to get every filter value buycycle currently offers, with the live count behind each one. | query, main_type, discipline, brand, max_values, ... |
| suggest | buycycle's own search-box suggestions for a few letters: the completion terms it would offer and the products it would preview under them. | Pricing teams call suggest to get buycycle's own search-box suggestions for a few letters. | query, include_pii |
| markets | The storefronts buycycle runs, straight from the site's own country table: country code and name, the currency that storefront prices in, and the languages it serves. These are the values `market`, `language` and the search filter `country` take. | Marketplace operators call markets to get the storefronts buycycle runs, straight from the site's own country table. | include_pii |
Call search from your stack
curl -X POST https://api.reefapi.com/buycycle/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"specialized tarmac","condition":["VERY_GOOD"],"frame_material":["carbon"],"sort":"price_desc"}'import requests
r = requests.post(
"https://api.reefapi.com/buycycle/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "specialized tarmac",
"condition": [
"VERY_GOOD"
],
"frame_material": [
"carbon"
],
"sort": "price_desc"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/buycycle/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "specialized tarmac",
"condition": [
"VERY_GOOD"
],
"frame_material": [
"carbon"
],
"sort": "price_desc"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.buycycle.search with {"query":"specialized tarmac","condition":["VERY_GOOD"],"frame_material":["carbon"],"sort":"price_desc"}.Who uses this API and why
- Price a used bike before buying or selling: filter by brand, model family, model year, frame size and condition, sort by price, and read the asking price next to the MSRP and buycycle's own market-price verdict.
- Track the European second-hand market for one model over time - Tarmac, Aeroad, Stumpjumper - with live counts per brand, family, frame material and condition.
- Feed a bike-shop or trade-in tool: pull commercial sellers only, with frame size, groupset and condition on every row, and the shipping cost and buyer-protection total on detail.
- Build a cross-border deal finder: the same catalogue priced in nine currencies across 28 storefronts, with a filter for the country the bike physically sits in.
- Watch new listings: sort by newest and poll for a brand, size and price band - the top rows are timestamped minutes old.
Questions developers ask before integrating
Do I need a buycycle account?
No. Everything here is read logged out, and you call reefapi.com from anywhere.
Which countries does it cover?
One pan-European catalogue of 125,567 listings, readable through any of 28 storefronts: Germany, Austria, Switzerland, France, Italy, Spain, Portugal, Netherlands, Belgium, Luxembourg, Ireland, Denmark, Sweden, Finland, Poland, Czech Republic, Slovakia, Hungary, Romania, Bulgaria, Croatia, Slovenia, Greece, Estonia, Latvia, Lithuania, Monaco and the United States. We called all 28 with the same listing and all 28 answered, each in its own currency: EUR 2,730, CZK 69,291, DKK 21,228, HUF 1,037,602, PLN 12,417, SEK 31,958, CHF 2,659, USD 3,192, GBP 2,408.
Can I filter the way the website does?
Yes, and every filter was checked against the unfiltered count of 125,567 in the same run: bikes 53,759, road and gravel 33,847, road bikes 24,739, Specialized 5,851, Canyon 2,326, the Tarmac family 1,354, frame size M 21,120, carbon 38,297, disc brakes 42,457, electronic shifting 19,499, e-bikes 6,380, framesets 3,805, commercial sellers 30,638, items in Germany 24,877, 1,000 to 4,000 of price 34,093, model years 2023-2024 21,853. Combining them narrows properly: road and gravel 33,838, plus carbon 27,939, plus Very good 13,549, plus commercial sellers 2,180.
How do I get from a search row to the full bike?
Pass the row's id to detail - the slug or the full product URL work too. Twelve ids taken from search across bikes, cycling gear and running all resolved to the same record, 12 of 12.
How accurate are the prices?
We compared eight listings against three things buycycle publishes independently of each other: the search index, the product page, and the page's own structured data. All three agreed on all eight, and so did buycycle's own plain-text rendering of the same listings. Brand, model year, frame size, groupset and condition also matched on 8 of 8 between search and detail.
How deep can I page?
10,000 rows per query - 193 pages of 52, or 50 pages of 200, which is buycycle's own hard limit on page size. The response tells you last_page up front and refuses anything past it instead of returning an empty page.
Do you return e-bikes, framesets and parts separately?
Yes. ebike=true returns the 6,380 assisted bikes, frameset=true the 3,805 frame-only listings, and main_type separates bikes from cycling gear, running, winter sports, outdoor, ball, water and racket sports. An e-bike's detail adds its motor, fork, rear shock and the rest of the component list.
What about kilometres ridden?
buycycle does not publish it as a field. We return the seller's description, where riders usually write it, and the "Low mileage" badge buycycle derives from that text - but we will not manufacture a number that is not there.
What is the buycycle API?
buycycle API is a ReefAPI endpoint group for europe's largest used-bike marketplace: listings with brand, model year, frame size, groupset, frame material, condition, price and the seller, across 28 storefront countries. It returns live JSON through POST requests under /buycycle/v1.
Is the buycycle API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. buycycle calls use the same shared credit balance as every other ReefAPI engine.
Do I need a buycycle login or account?
No login to buycycle 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 buycycle 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 buycycle API use?
buycycle 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 buycycle from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call buycycle actions with the same key, credit pool and JSON envelope used by normal REST requests.