TruckScout24
TruckScout24
/truckscout24/v1/search3 creditsSearch or browse the marketplace. Combine a keyword with any of the typed filters the source supports natively — category, manufacturer, model, machine type, condition, price band (net or gross), year of construction, first registration, hour meter, odometer, engine power, gross weight, fuel, emission class, gearbox, axles, suspension, colour, seller country and region, listing date, offer kind, trust seal, photos, video — and sort by price, year, listing date, update, manufacturer, type or model. Returns up to 25 rows a page with the price (and its VAT and incoterm wording), year, hour meter, odometer, condition, seller country and every property the result card prints. 🔴 Pass `strict_search=true` for any multi-word query: the source matches ANY word by default, so 'liebherr a 312' returns 55,623 listings loose and 2 strict. 🔴 Depth is capped by the source at 8 pages = 200 rows per query, so narrow rather than page — the filters are measured to bite hard (2,463 rows → 164 by manufacturer, → 797 by a 6-year window, → 517 by an hour-meter band, → 31 by an odometer floor).
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
| query | optional | — | Free-text keyword, exactly as typed into the source's own search box: a vehicle or machine type ('bagger', 'sattelzugmaschine', 'excavator'), a manufacturer, a model, or several words. 🔴 A MULTI-WORD QUERY WIDENS, IT DOES NOT NARROW, unless you also pass `strict_search=true`: the source splits on spaces and matches ANY token. Measured: 'liebherr a 312' returns 55,623 listings loose and exactly 2 with `strict_search=true`; 'bagger liebherr' 2,757 against 'bagger' alone 2,463; 'zzz-no-such-machine-anywhere-xyz' 8,617. A single unmatched word is an honest empty answer ('xyzzyplughfoo' → total 0, zero rows). Any multi-word query sent without `strict_search` comes back with a warning in meta saying so. |
| strict_search = false | optional | — | Require ALL the words of `query` to match instead of any one of them. The default is the source's own (off) so your totals match what the website shows, but for any query of more than one word this is almost always what you want: 'liebherr a 312' goes from 55,623 results to 2. Measured on single words too: 'bagger' 2,463 loose → 117 strict, because strict also matches the word as a whole rather than as a fragment. |
| category_id | optional | 1– | Browse one category using the source's own numeric id, at ANY level of the tree (8 = construction plant, 105 = excavators, 7 = transport & commercial vehicles, 246 = flatbed/curtain-side trucks, 252 = tractor units, 42 = forklifts & warehouse equipment, 4 = agricultural, 2357 = caravans & motorhomes). Measured to bite at every level: 8 → 9,535, 132 → 645. Get the ids from the `categories` or `suggest` action, or from any `ts-cat-<id>` URL. Combines with `query` and every filter. |
| category_slug | optional | — | Browse a category by the source's own URL path instead of by id. This exists because a minority of the child categories the source links are slug-only — its own link carries no numeric id — and `categories` returns `category_id: null` plus this slug for them. Pass it exactly as `categories` returns it ('baumaschinen/gebraucht/grader'). Measured to filter and page identically to an id (645 → 283 used → 26 in Germany). Ignored if `category_id` is also given. |
| manufacturer | optional | — | Manufacturer, spelled as the source's own facet spells it ('Liebherr', 'Mercedes-Benz', 'MAN', 'Caterpillar', 'DOOSAN' — the case is the source's). Pass a comma-separated list or a JSON array for several; several values widen (OR). Read the available spellings from `facets.manufacturers`. Measured to bite: query=bagger 2,463 → 164 for Liebherr, → 385 for Liebherr or Caterpillar. |
| model | optional | — | Model name as the source spells it. Pair it with `manufacturer` — the `suggest` action's `products` bucket returns valid manufacturer+model pairs, which is the way to avoid a spelling the source would silently drop. |
| machine_type | optional | — | The vehicle/machine-type name in that market's language, as printed on the first line of every result ('Mobilbagger', 'Kipper', 'Sattelzugmaschine'). Narrower than `query` because it matches the typed field rather than the whole listing. Measured to bite: 2,463 → 183 for 'Mobilbagger'. |
| condition | optional | used · new · ex-display machine · defective | Condition class. Pass a comma-separated list for several. 🔴 An unknown value is NOT an error on this source — it is dropped and you get the unfiltered catalogue, so this engine validates the value instead of forwarding it ('brandnew' returned the control's own 2,463 rows). Measured to bite: 2,463 → 2,003 used, 380 new. |
| year_min | optional | 1900–2100 | Earliest year of construction, inclusive. 🔴 The source's own field takes a UNIX TIMESTAMP, and a bare year is not rejected — it is MISREAD as a few seconds after 1970, so 'from 2015' silently becomes 'from 1970' (measured: 2,152 results with page-1 years 1980-2022). This engine sends the timestamp the source's own select carries, and the filter then bites exactly: 2,463 → 1,579, every page-1 row 2015-2026. |
| year_max | optional | 1900–2100 | Latest year of construction, inclusive. Same timestamp conversion as `year_min` — a bare year here is even worse, returning 2 listings instead of 80. Measured: year_max=2000 → 80, every row ≤ 2000; year_min 2015 + year_max 2020 → 797. |
| first_registration_min | optional | 1900–2100 | Earliest year of first registration (road vehicles). Same UNIX-timestamp trap as `year_min`: a bare year is misread rather than rejected (measured 164 against the correct 65). |
| first_registration_max | optional | 1900–2100 | Latest year of first registration. 🔴 The source's own option for this bound is 1 DECEMBER of the year, not 31 December, so that is what is sent — which means a value of 2024 excludes vehicles first registered in December 2024. Said out loud rather than quietly rounded, because the alternative is sending a timestamp the source's own UI never sends. |
| operating_hours_min | optional | 0– | Minimum hour-meter reading. This is the machine's HOUR meter, kept separate from `mileage_min` (the odometer) so hours and kilometres are never compared. Measured to bite: 2,463 → 752 above 5,000 h. |
| operating_hours_max | optional | 0– | Maximum hour-meter reading. Measured to bite: 2,463 → 517 under 2,000 h. |
| mileage_min | optional | 0– | Minimum odometer reading in km. A property of road vehicles (trucks, tractor units, vans, buses) and self-propelled plant, separate from the hour meter. Measured to bite: 2,463 → 31 above 100,000 km. |
| mileage_max | optional | 0– | Maximum odometer reading in km. Pair it with `mileage_min` for a band: a band is what makes a comparable set, because the odometer is the single biggest price driver on a road vehicle. |
| power_min | optional | 0– | Minimum engine power in kW (the unit the source's own filter uses; it prints both kW and PS/HP in the data). Measured to bite: 2,463 → 209 for 100-200 kW. |
| power_max | optional | 0– | Maximum engine power in kW — the unit the source's own filter uses, even though it prints both kW and PS/HP in the data it returns. |
| total_weight_min | optional | 0– | Minimum gross/overall weight in kg. Measured to bite: 2,463 → 128 above 10,000 kg. |
| total_weight_max | optional | 0– | Maximum gross/overall weight in kg. This is the plated weight the source publishes as `Gesamtgewicht` / `Overall weight`, not the empty weight. |
| price_min | optional | 0– | Minimum price in EUR. Net of VAT unless you also pass `price_band_gross`. Measured to bite: 2,463 → 1,113 for 10,000-50,000 EUR. |
| price_max | optional | 0– | Maximum price in EUR. Net of VAT unless `price_band_gross` is also set — on this source a seller may price either way, so a band without that flag is a band on the net figure. |
| price_band_gross = false | optional | — | Apply `price_min`/`price_max` to the GROSS (VAT-inclusive) price instead of the net one. Measured to change the answer: the same 10,000-50,000 band returns 1,113 net and 981 gross. It has no effect without a price band. |
| with_price_only = false | optional | — | Only listings that publish a price, dropping the 'price on request' ones. Measured to bite: 2,463 → 2,159. Note the inverse is not available: the source ignores `has-price=0` (it returned the full 2,463), so there is no 'price-on-request only' filter to offer. Filter the `price_on_request` field instead. |
| country | optional | — | Seller country as an ISO-3166 alpha-2 code, UPPER CASE ('DE', 'NL', 'AT', 'PL'). Comma-separate for several. 🔴 The source is case sensitive and silently drops a lower-case code — measured: `countries[]=de` answered '0 results' over the unfiltered catalogue — so this engine upper-cases before sending. Measured to bite: 2,463 → 1,457 DE, → 275 NL. |
| region | optional | — | Region/state inside `country`, by the source's OWN NAME, not a code ('Bayern', 'Niedersachsen', 'Nordrhein-Westfalen'). 🔴 A code is silently dropped upstream (`regions[DE][]=BY` answered '0 results' over the unfiltered catalogue). Requires `country`, because the source nests regions under a country. Read the valid names from `facets.regions`; note the source itself publishes both 'Bayern' and 'Bavaria' as separate region values. Measured to bite: country=DE 1,457 → 475 Bayern. |
| listing_type | optional | classified · auction · rental | Restrict to one kind of offer. Measured to bite on query=bagger: classified 2,462, auction 1, rental 47 (and 306 auctions / 1,173 rentals across the whole catalogue). 🔴 Two further flags exist in the source's own form, `is-spare-parts` and `is-buy-now`, and returned ZERO rows for every combination tried (alone, with a keyword, inside a category), so they are not offered rather than offered as filters that always answer nothing. |
| trust_seal_only = false | optional | — | Only listings from dealers carrying the marketplace's own trust seal. Measured to bite: 2,463 → 540. |
| with_images_only = false | optional | — | Only listings with at least one photo. Measured: 2,463 → 2,452, i.e. it barely narrows anything on this marketplace. |
| with_video_only = false | optional | — | Only listings with a video. Measured to bite: 2,463 → 204. |
| description_contains | optional | — | A word that must appear in the seller's free-text description. This searches the prose rather than the typed fields, which is how to find equipment the source has no field for. Measured to bite: 2,463 → 148 for 'hydraulik'. |
| fuel_type | optional | gasoline · diesel · electric · gas · hybrid · hydrogen | Fuel type, by the source's own value. Measured to bite: 2,463 → 581 diesel. 🔴 An unknown value ('petrol') is dropped and answers '0 results' over the unfiltered catalogue, so it is validated here. |
| emission_class | optional | euro1 · euro2 · euro3 · euro4 · euro5 · euro6 · euro6b · euro6c · euro6d · euro6d-temp · euro6e · euro7 · none | Euro emission class, by the source's own value. Measured to bite: 2,463 → 23 for euro6. |
| gearing_type | optional | automatic · semi-automatic · hydrostat · converter · mechanical · other | Gearbox type. Measured to bite: 2,463 → 113 automatic. |
| suspension | optional | steel · steel-air · hydraulics · air · parabolic leaf (spring) · other | Suspension type, by the source's own value. The source PRINTS the market's own word (`Blatt-Luft`) and FILTERS on the code (`steel-air`); the rows this API returns carry the code, so reading a row and asking for more like it round-trips. |
| axle_configuration | optional | 1 axle · 2 axles · 3 axles · > 3 axles | Number of axles, by the source's own value. Measured to bite: 2,463 → 56 for '2 axles'. |
| color | optional | beige · blue · brown · bronze · dark red · yellow · gold · grey · grey-black · green · light blue · light grey · light green · orange · original · red · black · silver · other · traffic orange · violet · white | Colour, by the source's own value (`yellow`, not `Gelb`). Same round-trip rule as `suspension`: the printed word is mapped to the filter's own code. |
| mast_type | optional | telescopic · duplex · free lift with tel. boom · mono · simplex · other · triplex | Forklift mast type — only meaningful inside the forklift categories. |
| listed_after | optional | — | Only listings put online on or after this date (YYYY-MM-DD). This is how to poll a narrow query for what is new. Measured to bite: 2,463 → 169 for the last seven days. |
| listed_before | optional | — | Only listings put online before this date (YYYY-MM-DD). Measured to bite: 2,463 → 477 for listings older than a year. |
| auction_ends_before | optional | — | Only auctions ending before this date (YYYY-MM-DD). Measured to bite: the 306 live auctions → 106 ending inside a week. |
| listing_id | optional | — | Look one listing up inside a search. Note the source pads the answer: it reports '(1)' and renders 25 cards, 24 of which match nothing in the query. This engine cuts them. For one listing in full use the `detail` action instead. |
| reference_number | optional | — | The seller's own reference number, as printed on the listing. Measured to bite: 2,463 → 1 (plus the padding this engine cuts). |
| machine_number | optional | — | The seller's own machine or vehicle number, printed on the listing as 'Fahrzeugnummer' / 'Vehicle ID number'. Different from `reference_number`: that is the advert's reference, this is the vehicle's. |
| sort = relevance | optional | relevance · price_asc · price_desc · newest · oldest · year_desc · year_asc · updated_desc · updated_asc · manufacturer_asc · manufacturer_desc · machine_type_asc · machine_type_desc · model_asc · model_desc | Result order. 🔴 Only orders MEASURED to bite are offered: the source accepts an unknown sort field with HTTP 200 and silently falls back to relevance (measured for 'referenz', 'laufzeit', 'einstelldatum' and a nonsense value), and its own dropdown is not the full set of values it honours. `meta.sort_applied` reports the sort the SOURCE says it used, so you never have to trust that the parameter arrived. Sorting by distance is deliberately NOT offered: the source's distance is measured from whoever asks, which for an API is the server, so the same call would order differently from different machines. |
| page = 1 | optional | 1–8 | Result page, 25 rows a page. 🔴 Capped at 8 by the SOURCE: page 9 answers HTTP 404 for a 2,463-row query and for a 45,694-row one alike (pages 10, 20 and 100 too), so at most 200 rows are retrievable per query however large `total` is. It does not silently repeat the last page. To go deeper, narrow — every filter here was measured to bite. |
| include_facets = false | optional | — | Add the source's own live filter counts for this query to `meta.facets` without a second request (the same page carries them). |
| include_description = true | optional | — | Include each row's description preview (default true). The decoy line the source injects is removed and the number removed is reported per row. |
/truckscout24/v1/detail3 creditsOne listing in full, by id. Returns the vehicle or machine (type, manufacturer, model, year, condition, functionality, hour meter, odometer, the seller's own vehicle number), the price with its previous price, gross figure, VAT treatment and incoterm, every technical property the seller typed — grouped the way the source groups them, each with a parsed number and unit — the boolean equipment badges, the offer block (listing code, reference number, last update, and an auction's start and end), the seller's street, postcode, town and country, the dealer id with their member-since year, listings online and trust seal, the category breadcrumb, every gallery image and the full description with the injected decoy line removed. The price is cross-checked against the page's own schema.org product data and any disagreement is reported, not hidden.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| listing_id | required | — | The listing's numeric id. Accepted as the plain number (21924313), with the source's own 'A' prefix, in its dashed display form (219-24-313 / A219-24-313) or as a full listing URL ending in /tsp/ts-21924313. Get ids from `search`. |
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
/truckscout24/v1/categories1 creditThe marketplace's own category tree with live per-category listing counts: the nine top-level sectors (transport & commercial vehicles, construction plant, forklifts & warehouse equipment, agricultural, caravans & motorhomes, municipal technology, warehouse technology, recycling, workshop equipment) with the numeric ids every other action's `category_id` takes. Pass a `category_id` to drill into that sector's children — the FULL list the source publishes, not its 'top' shortlist — which is how you get from 9,535 construction machines to the 2,053 excavators or the 1,819 access platforms. Every count is the source's own live figure.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
| category_id | optional | 1– | Browse one category using the source's own numeric id, at ANY level of the tree (8 = construction plant, 105 = excavators, 7 = transport & commercial vehicles, 246 = flatbed/curtain-side trucks, 252 = tractor units, 42 = forklifts & warehouse equipment, 4 = agricultural, 2357 = caravans & motorhomes). Measured to bite at every level: 8 → 9,535, 132 → 645. Get the ids from the `categories` or `suggest` action, or from any `ts-cat-<id>` URL. Combines with `query` and every filter. |
/truckscout24/v1/facets2 creditsThe source's own live filter counts for a query: which categories, sub-categories, manufacturers, countries, regions, conditions, fuel types, emission classes, gearbox types, suspensions, colours, mast types and axle configurations have stock, and how much. This is how you learn the exact spelling a filter wants (the source is case sensitive and wants region NAMES, not codes) and how to narrow a query that is deeper than the 200-row retrievable ceiling. The source publishes its top 15 per checkbox group. 🔴 The radius bands it also prints are NOT returned: their counts are computed from the caller's own location, which for an API is the server's.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
| query | optional | — | Free-text keyword, exactly as typed into the source's own search box: a vehicle or machine type ('bagger', 'sattelzugmaschine', 'excavator'), a manufacturer, a model, or several words. 🔴 A MULTI-WORD QUERY WIDENS, IT DOES NOT NARROW, unless you also pass `strict_search=true`: the source splits on spaces and matches ANY token. Measured: 'liebherr a 312' returns 55,623 listings loose and exactly 2 with `strict_search=true`; 'bagger liebherr' 2,757 against 'bagger' alone 2,463; 'zzz-no-such-machine-anywhere-xyz' 8,617. A single unmatched word is an honest empty answer ('xyzzyplughfoo' → total 0, zero rows). Any multi-word query sent without `strict_search` comes back with a warning in meta saying so. |
| strict_search = false | optional | — | Require ALL the words of `query` to match instead of any one of them. The default is the source's own (off) so your totals match what the website shows, but for any query of more than one word this is almost always what you want: 'liebherr a 312' goes from 55,623 results to 2. Measured on single words too: 'bagger' 2,463 loose → 117 strict, because strict also matches the word as a whole rather than as a fragment. |
| category_id | optional | 1– | Browse one category using the source's own numeric id, at ANY level of the tree (8 = construction plant, 105 = excavators, 7 = transport & commercial vehicles, 246 = flatbed/curtain-side trucks, 252 = tractor units, 42 = forklifts & warehouse equipment, 4 = agricultural, 2357 = caravans & motorhomes). Measured to bite at every level: 8 → 9,535, 132 → 645. Get the ids from the `categories` or `suggest` action, or from any `ts-cat-<id>` URL. Combines with `query` and every filter. |
| category_slug | optional | — | Browse a category by the source's own URL path instead of by id. This exists because a minority of the child categories the source links are slug-only — its own link carries no numeric id — and `categories` returns `category_id: null` plus this slug for them. Pass it exactly as `categories` returns it ('baumaschinen/gebraucht/grader'). Measured to filter and page identically to an id (645 → 283 used → 26 in Germany). Ignored if `category_id` is also given. |
| manufacturer | optional | — | Manufacturer, spelled as the source's own facet spells it ('Liebherr', 'Mercedes-Benz', 'MAN', 'Caterpillar', 'DOOSAN' — the case is the source's). Pass a comma-separated list or a JSON array for several; several values widen (OR). Read the available spellings from `facets.manufacturers`. Measured to bite: query=bagger 2,463 → 164 for Liebherr, → 385 for Liebherr or Caterpillar. |
| machine_type | optional | — | The vehicle/machine-type name in that market's language, as printed on the first line of every result ('Mobilbagger', 'Kipper', 'Sattelzugmaschine'). Narrower than `query` because it matches the typed field rather than the whole listing. Measured to bite: 2,463 → 183 for 'Mobilbagger'. |
| condition | optional | used · new · ex-display machine · defective | Condition class. Pass a comma-separated list for several. 🔴 An unknown value is NOT an error on this source — it is dropped and you get the unfiltered catalogue, so this engine validates the value instead of forwarding it ('brandnew' returned the control's own 2,463 rows). Measured to bite: 2,463 → 2,003 used, 380 new. |
| year_min | optional | 1900–2100 | Earliest year of construction, inclusive. 🔴 The source's own field takes a UNIX TIMESTAMP, and a bare year is not rejected — it is MISREAD as a few seconds after 1970, so 'from 2015' silently becomes 'from 1970' (measured: 2,152 results with page-1 years 1980-2022). This engine sends the timestamp the source's own select carries, and the filter then bites exactly: 2,463 → 1,579, every page-1 row 2015-2026. |
| year_max | optional | 1900–2100 | Latest year of construction, inclusive. Same timestamp conversion as `year_min` — a bare year here is even worse, returning 2 listings instead of 80. Measured: year_max=2000 → 80, every row ≤ 2000; year_min 2015 + year_max 2020 → 797. |
| operating_hours_min | optional | 0– | Minimum hour-meter reading. This is the machine's HOUR meter, kept separate from `mileage_min` (the odometer) so hours and kilometres are never compared. Measured to bite: 2,463 → 752 above 5,000 h. |
| operating_hours_max | optional | 0– | Maximum hour-meter reading. Measured to bite: 2,463 → 517 under 2,000 h. |
| mileage_min | optional | 0– | Minimum odometer reading in km. A property of road vehicles (trucks, tractor units, vans, buses) and self-propelled plant, separate from the hour meter. Measured to bite: 2,463 → 31 above 100,000 km. |
| mileage_max | optional | 0– | Maximum odometer reading in km. Pair it with `mileage_min` for a band: a band is what makes a comparable set, because the odometer is the single biggest price driver on a road vehicle. |
| price_min | optional | 0– | Minimum price in EUR. Net of VAT unless you also pass `price_band_gross`. Measured to bite: 2,463 → 1,113 for 10,000-50,000 EUR. |
| price_max | optional | 0– | Maximum price in EUR. Net of VAT unless `price_band_gross` is also set — on this source a seller may price either way, so a band without that flag is a band on the net figure. |
| with_price_only = false | optional | — | Only listings that publish a price, dropping the 'price on request' ones. Measured to bite: 2,463 → 2,159. Note the inverse is not available: the source ignores `has-price=0` (it returned the full 2,463), so there is no 'price-on-request only' filter to offer. Filter the `price_on_request` field instead. |
| country | optional | — | Seller country as an ISO-3166 alpha-2 code, UPPER CASE ('DE', 'NL', 'AT', 'PL'). Comma-separate for several. 🔴 The source is case sensitive and silently drops a lower-case code — measured: `countries[]=de` answered '0 results' over the unfiltered catalogue — so this engine upper-cases before sending. Measured to bite: 2,463 → 1,457 DE, → 275 NL. |
| region | optional | — | Region/state inside `country`, by the source's OWN NAME, not a code ('Bayern', 'Niedersachsen', 'Nordrhein-Westfalen'). 🔴 A code is silently dropped upstream (`regions[DE][]=BY` answered '0 results' over the unfiltered catalogue). Requires `country`, because the source nests regions under a country. Read the valid names from `facets.regions`; note the source itself publishes both 'Bayern' and 'Bavaria' as separate region values. Measured to bite: country=DE 1,457 → 475 Bayern. |
| listing_type | optional | classified · auction · rental | Restrict to one kind of offer. Measured to bite on query=bagger: classified 2,462, auction 1, rental 47 (and 306 auctions / 1,173 rentals across the whole catalogue). 🔴 Two further flags exist in the source's own form, `is-spare-parts` and `is-buy-now`, and returned ZERO rows for every combination tried (alone, with a keyword, inside a category), so they are not offered rather than offered as filters that always answer nothing. |
| description_contains | optional | — | A word that must appear in the seller's free-text description. This searches the prose rather than the typed fields, which is how to find equipment the source has no field for. Measured to bite: 2,463 → 148 for 'hydraulik'. |
| fuel_type | optional | gasoline · diesel · electric · gas · hybrid · hydrogen | Fuel type, by the source's own value. Measured to bite: 2,463 → 581 diesel. 🔴 An unknown value ('petrol') is dropped and answers '0 results' over the unfiltered catalogue, so it is validated here. |
| emission_class | optional | euro1 · euro2 · euro3 · euro4 · euro5 · euro6 · euro6b · euro6c · euro6d · euro6d-temp · euro6e · euro7 · none | Euro emission class, by the source's own value. Measured to bite: 2,463 → 23 for euro6. |
| sort = relevance | optional | relevance · price_asc · price_desc · newest · oldest · year_desc · year_asc · updated_desc · updated_asc · manufacturer_asc · manufacturer_desc · machine_type_asc · machine_type_desc · model_asc · model_desc | Result order. 🔴 Only orders MEASURED to bite are offered: the source accepts an unknown sort field with HTTP 200 and silently falls back to relevance (measured for 'referenz', 'laufzeit', 'einstelldatum' and a nonsense value), and its own dropdown is not the full set of values it honours. `meta.sort_applied` reports the sort the SOURCE says it used, so you never have to trust that the parameter arrived. Sorting by distance is deliberately NOT offered: the source's distance is measured from whoever asks, which for an API is the server, so the same call would order differently from different machines. |
/truckscout24/v1/suggest1 creditThe source's own autocomplete for a typed prefix, in four buckets: machine/vehicle types, manufacturers, categories (with their numeric id or slug) and products (manufacturer + model pairs). Use it to turn whatever a user typed into values the `machine_type`, `manufacturer`, `model` and `category_id` filters accept, instead of guessing a spelling the source would silently drop.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| query | required | — | What the user has typed so far, at least 2 characters — the source's own autocomplete does not answer a shorter prefix. |
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
| category_id | optional | 1– | Browse one category using the source's own numeric id, at ANY level of the tree (8 = construction plant, 105 = excavators, 7 = transport & commercial vehicles, 246 = flatbed/curtain-side trucks, 252 = tractor units, 42 = forklifts & warehouse equipment, 4 = agricultural, 2357 = caravans & motorhomes). Measured to bite at every level: 8 → 9,535, 132 → 645. Get the ids from the `categories` or `suggest` action, or from any `ts-cat-<id>` URL. Combines with `query` and every filter. |
/truckscout24/v1/dealers2 creditsThe dealer directory for one category: the dealers themselves, 100 a page, each with company name, street, postcode, town, country, region, trust seal and the dealer id the `seller` action takes. This is the supplier-side view of the marketplace — the source's own figure is over 4,500 dealers. 🔴 The distance it prints beside each dealer, and its own default ordering BY that distance, are both measured from the caller's location and are neither returned nor offered.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| category_id | required | 1– | The category whose dealers to list. The source's dealer directory is organised per category and has no 'all dealers' page. Use `categories` for the ids. |
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
| page = 1 | optional | 1– | Directory page, 100 dealers a page. A page past the last one answers NOT_FOUND; the source publishes no dealer total. |
| sort = name | optional | name · postcode · country | Directory order. 🔴 The source's OWN default order is distance from the viewer, which for an API is the server — the same page would come back in a different order from a different container — so this engine always sends an explicit stable order and does not offer the distance one. |
/truckscout24/v1/seller2 creditsOne dealer's public profile by id: company name, postal address (street, postcode, town, region, country), their own description of the business, the vehicle categories they deal in, the searches the source cross-links from their page, and the trust seal. This is where a listing's seller NAME comes from — the listing page itself keeps it behind a login. 🔴 The listing cards on a dealer's page are login-walled placeholder markup (every one carries the dealer's own name as its title and has listing id 0), so they are deliberately not returned; use `search` for real stock. Contact-person names, phone numbers and e-mail addresses are never returned.
| Parameter | Allowed / range | Description | |
|---|---|---|---|
| dealer_id | required | — | The dealer's numeric id, as returned by `dealers`, by `search` (each row's `seller_id`) or by `detail` (`listing.seller.dealer_id`). A dealer profile URL containing /tsd/75149/ is accepted too. |
| market = de | optional | de · at · com | Which TruckScout24 host to read. 🔴 This picks the LANGUAGE of the labels, not a different catalogue: the listings are one shared pool and the price is the same number in the same currency on every host (measured: listing 21924313 is EUR 16,900 on all of them — the site does not convert currency). Use 'de' for German wording and 'com' for English. The wider TruckScout24 network has 25 further hosts; only these three have their label vocabulary measured and mapped here, so the others answer MARKET_UNAVAILABLE rather than returning fields this engine cannot name. One honest caveat: the source's own machine-type translation is unreliable (listing 22233387 is 'LKW mit Pritsche & Plane' on .de and 'Beverage' on .com), which is why 'de' is the default. |
curl -X POST https://api.reefapi.com/truckscout24/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"bagger","market":"de","page":1}'{
"ok": true,
"data": { /* the result */ },
"meta": {
"latency_ms": 240,
"record_count": 12,
"completeness_pct": 100
},
"error": null
}Measured at 60 requests a second across the fleet, with no central bottleneck. Volume pricing is on request, and per-key limits are raised for high-volume accounts.
Tell us a site we do not cover yet and it becomes an engine. A customer asked for bestprice.gr on a Sunday and it was in the catalog the next day.
Median time from a question in the live chat to the first answer, measured across every answered conversation. Setup help included, no support tier to buy.
No per-site plans and no separate subscriptions. One key and one credit pool across the whole catalog, so adding a source costs nothing up front.
Planning something large? Tell us the volume and the sources and we will come back with what it costs and what we would have to build.