Search the used cars advertised for sale on UK dealer websites today, and the cars sold in the last 90 days, by any filter: make, model, trim, year, fuel, gearbox, price, mileage, location, dealer and more. Get statistics, counts and price bands over the whole market, the full advert history of a registration, and the UK dealer directory with each dealer's stock.
Every endpoint is a JSON POST under https://www.dealerpricing.co.uk/api with your key in the X-API-Key header, as in the API documentation. Field by field detail is in the API reference and the OpenAPI file.
Endpoints and prices
Prices follow what a call costs us: one data request is 10p Pay As You Go, 8p Starter, 5p Pro, 3p Enterprise. A call that needs two requests costs twice that. Prices are per call, in pence, at your package.
One dealer's live stock with stock age, price statistics and make mix.
10p
8p
5p
3p
Monthly packages get their fee back as plan credit to spend on calls. Live keys only: sandbox calls are free.
Paging and bulk mode
Results per call:rows 1 to 50 (default 10). Each call is one data request and one price.
More results: send start 0 for results 1 to 50, 50 for 51 to 100, 100 for 101 to 150, and so on. total_found says how many match and more_available says whether another page exists. start + rows is at most 10,000: narrow the filters to see beyond that.
Bulk mode:bulk: true on listings and sold listings returns up to 1,000 light rows a call (rows 1 to 1,000, default 100: id, registration, price, mileage, year, make, model, trim, days on market, days at dealer, dealer id, location and one photo), priced as 5 requests. No counts, statistics, bands, fields, photos or duplicates in this mode.
Counts, statistics and bands for free: on listings, facets, stats and range_bands come back in the same call at no extra cost. On sold data, one of them a call.
Smaller answers:fields keeps only the listing fields you name, and photos sets photo links per listing (0 to 10, default 3). Same price.
// Read every 2019 BMW 3 Series for sale, 50 at a time
let start = 0
do {
const res = await fetch('https://www.dealerpricing.co.uk/api/v1/market/listings', {
method: 'POST',
headers: { 'X-API-Key': YOUR_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ make: 'BMW', model: '3 Series', year_min: 2019, year_max: 2019, rows: 50, start })
}).then(r => r.json())
handle(res.data.listings)
if (!res.data.more_available) break
start += 50
} while (true)
Filters
The same names and values on every endpoint. Lists can be sent as a JSON array or a comma list. A field an endpoint does not take is refused with 400 INVALID_PARAMETER naming it, never silently ignored. Each endpoint below lists the fields it takes.
Vehicle
vrm: registration, no spaces needed
The registration to look up, without spaces. Sandbox keys take the published sandbox registrations.
Advert
listing_id: an adv_ id
The listing_id of an advert from any market listings answer (it starts adv_).
follow_relist: true or false
If this advert has ended and the same car was advertised again, return the newest advert instead.
Dealer filters
dealer_id: a dlr_ id
One dealer id (it starts dlr_), from a listing (dealer.dealer_id) or a dealer search.
Scope
scope: live or sold
Cars for sale now, or cars sold in the last 90 days. Sold means the advert ended and the car did not reappear within 7 days. Radius on sold data is at most 100 miles.
Make and model
make: text, or a list of up to 20
One or more makes, comma separated. Example: BMW,Audi.
exclude_make: text, or a list of up to 20
Leaves out every car of these makes. Use it when you have not picked makes to include.
model: text, or a list of up to 20
Model
variant: text, or a list of up to 20
The trim as dealers advertise it. Example: M Sport.
model_variant: text, or a list of up to 20
The model and trim together, exactly as the data spells them (see the model_variant counts). Example: Focus Titanium.
year_min, year_max: numbers, 1980 to 2027 (either end may be left out)
Model year from and to, both included. Example: 2018 to 2020.
First registration date window (YYYY-MM-DD), closer like-for-like than model year. Example: 2019-03-01 to 2019-08-31 for a 19 plate.For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
Specification
body_type: text, or a list of up to 20
Body type
fuel_type: text, or a list of up to 20
Fuel as the adverts spell it. Hybrids are "Petrol Electric Hybrid" or "Diesel Electric Hybrid". Use fuel_type counts to see every spelling.
transmission: Manual or Automatic
Gearbox
drivetrain: text, or a list of up to 20
4x2 = two-wheel drive (front or rear), 4x4 = four-wheel or all-wheel drive. FWD, RWD and 2WD count as 4x2; AWD and 4WD count as 4x4.
engine_size_min, engine_size_max: numbers, 0 to 9 (either end may be left out)
From and to, in litres. Example: 1.9 to 2.1 finds 2.0 litre cars.
doors: text, or a list of up to 20
For-sale data only: sold adverts do not record doors.For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
seats: text, or a list of up to 20
Seats
colour: text, or a list of up to 20
Colour
combined_mpg_min, combined_mpg_max: numbers, 0 to 999 (either end may be left out)
Combined mpg
ev_range_min, ev_range_max: numbers, 0 to 2000 (either end may be left out)
Electric range (miles)For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
battery_kwh_min, battery_kwh_max: numbers, 0 to 300 (either end may be left out)
Battery (kWh)For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
insurance_group: text
UK insurance group, 1 (cheapest) to 50.
ulez_compliant: true or false
Only cars that meet the London ULEZ rules. Send true; there is no "not compliant" filter.
Condition
write_off_category: list of A, B, S, N, C, D
Only cars recorded as written off in these categories. S and N can be repaired; A and B must not return to the road. C and D are the older (before October 2017) repairable categories.
exclude_write_off: list of A, B, S, N, C, D
Leaves out cars recorded in these write-off categories. Recommended for clean comparisons.
Price and mileage
vat_included: true or false
Yes = the advertised price includes VAT; No = VAT is added on top (common on vans). Most adverts do not say either way, so both leave those out.
price_min, price_max: numbers, 1 to 9999999 (either end may be left out)
Asking price from and to. Example: 10000 to 15000.
priced_only: true or false
On by default: adverts with no price are left out (they would sort first on a cheapest-first list). Send false to include them.
mileage_min, mileage_max: numbers, 0 to 999999 (either end may be left out)
Mileage
price_reduced: true or false
Only adverts whose price has been cut since first advertised.For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
price_change_min, price_change_max: numbers, -999999 to 999999 (either end may be left out)
The change in pounds since first advertised; negative = a cut. Example: -2000 to -500 finds cuts of £500 to £2,000.For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
Time on sale
days_on_market_min, days_on_market_max: numbers, 0 to 9999 (either end may be left out)
Days on sale in the current spell, across every dealer advertising it. (Every day ever advertised is days_listed in each listing.)
days_at_dealer_min, days_at_dealer_max: numbers, 0 to 9999 (either end may be left out)
Days advertised by its current dealer. 120 and up finds aged stock.
listed_within_days: whole number, 1 to 90
New arrivals: adverts first seen in the last N days.For-sale data only: sold adverts do not record it, so it is refused (free) on sold data and on the overview.
active_from, active_to: dates, YYYY-MM-DD
Sold data only: cars that were for sale at some point in this window (YYYY-MM-DD; either end may be left open).
Location
postcode: text
Centre point for a radius search and for sorting by distance. Use this or latitude and longitude.
latitude: number, 49 to 61
Centre point instead of a postcode; send longitude too.
longitude: number, -9 to 2
Longitude
radius: whole number, 1 to 200
Only cars within this many miles of the postcode or latitude and longitude. Up to 200 miles on live data, 100 on sold data.
region: england or scotland or wales or northern_ireland
Country
county: text
County
city: text
Town or city
Dealer directory
dealer_type: franchise or independent
Franchise = a main dealer for a brand. Independent = any other trader.
dealer_id: dlr_ ids, up to 20
Only cars from these dealers (ids start dlr_, from a listing or a dealer search).
exclude_dealer_id: dlr_ ids, up to 20
Leaves out these dealers, for example your own stock when you look at competitors.
dealer_name: text
The exact trading name, not case sensitive.
group_name: text
Every site of a dealer group.
Results
page: whole number, 1 to 20
Advert history comes 50 adverts a page. Page 2 = adverts 51 to 100.
sort_by: price or mileage or days_on_market or days_at_dealer or first_listed or last_seen or distance or price_change_pct or combined_mpg
One field. Default: price, or distance when a location is given.
sort_by (dealer search): distance or newest
Dealer search only: distance (needs a postcode, or latitude and longitude) or newest dealers first.
sort_order: asc or desc
Order
rows: whole number, 0 to 1000
Results per call: 1 to 50 (default 10). With bulk: true, 1 to 1,000 light rows (default 100).
start: whole number, 0 to 9999
How many results to skip: 0 for results 1 to 50, 50 for 51 to 100, and so on. start + rows is at most 10,000.
bulk: true or false
Up to 1,000 light rows a call (id, registration, price, mileage, year, make, model, trim, days, dealer id, location, one photo), priced as five requests. No counts, statistics, bands, fields, photos or duplicates in this mode; only adverts with a price, mileage and days on market are included.
Extras
facets: list of up to 5 fields; facet_limit 1 to 1,000; facet_sort count or alpha
Counts of matching cars for each value of a field, over every matching car (not just this page). Up to 5 fields; facet_limit (1 to 1,000, default 20) values each; facet_sort count or alpha.
stats: list of price, mileage, days_on_market, days_at_dealer, days_listed, days_listed_180
Count, min, max, mean, median, standard deviation and percentiles over every matching car. Medians are approximate.
range_bands: up to 3 of { field, from, to, step }, at most 199 bands each; fields price, mileage, days_on_market, days_at_dealer, days_listed, days_listed_180, combined_mpg, ev_range
Counts of matching cars in equal bands: [{ "field": "price", "from": 0, "to": 40000, "step": 5000 }]. At most 3 fields and 200 bands each; also counts below and above the range.
fields: list of fields (32 available)
Return only these fields for each listing (same price). Leave empty for every field.
photos: whole number, 0 to 10
How many photo links per listing (default 3, 0 for none). One advert in full sends every photo unless this limits it.
include_duplicates: true or false
By default one row per car even if several sites advertise it. Send true to get every advert of the same car.
Rules: send a postcode or latitude and longitude, not both; a radius or a distance sort needs one of them (radius up to 200 miles on live data, 100 on sold data and the overview); a make cannot be both included and left out, nor can a dealer or a write-off category; price_reduced and the price change range cannot be sent together.
Each endpoint
Market listings
POST /api/v1/market/listings
Search every UK car for sale now by any filter, location and sort, 1 to 50 results per call.
Price per call
Pay As You Go 10p, Starter 8p, Pro 5p, Enterprise 3pbulk: Pay As You Go 50p, Starter 40p, Pro 25p, Enterprise 15p
/v1/market/active, /v1/market/sold, /v1/market/insights and /v1/pricing/insights still find cars like the registration you send. They now also take these optional filters, with the same names and values as above. Send none and they answer exactly as before, at the same price.
fuel_type: text, or a list of up to 20
mileage_min, mileage_max: numbers, 0 to 999999 (either end may be left out)
postcode: text
radius: whole number, 1 to 200
exclude_write_off: list of A, B, S, N, C, D
dealer_type: franchise or independent
Radius: up to 200 miles on /v1/market/active and 100 on the others (they use sold data). Every listing on /v1/market/active and /v1/market/sold also carries listing_id (adv_...), which you can send to one advert in full.
Sandbox
Sandbox keys are free. The market searches answer from a stored sample: about 100 adverts for sale and 100 sold for each test model at GET /v1/sandbox/market-presets. Leave make and model out to search the whole sample, or name any of its makes and models. Every filter, sort, paging, count, statistic and band is worked out on the sample, so totals describe the sample, not the market.
Sandbox data is fictional. Each answer has exactly the fields a live answer has, filled in the same places, but every advert, dealer and seller is made up: names, addresses, phone numbers (Ofcom's drama range, 01632 960xxx), email addresses and websites (on example.com), registrations (age identifier 00, never issued), links and photos (sample drawings). Sandbox ids start the same way as live ones (adv_, dlr_) but only work with sandbox keys.
Dealer search covers the test areas (postcode N1 7GU, B5 4BU, M1 1AE); dealer detail and stock cover the dealers listed there; one advert in full covers adverts from sandbox answers.
Advert history and live adverts use the sandbox registrations at GET /v1/sandbox/vrms, with made-up adverts that are the same every time. A registration in the Mileage Check category has a later advert showing fewer miles, so the mileage check reports it; a scrapped car has no live adverts.
On the registration endpoints (/v1/market/insights, /v1/pricing/insights) the filters narrow the sold figures as well as the live adverts, as they do on live keys: the sandbox works them out from a fictional sold sample shaped like the stored figures.
A make or model the sample does not hold, and anything outside the test areas, dealers and adverts, answers 404 SANDBOX_QUERY_NOT_AVAILABLE (free). Sandbox answers carry meta.sample_note; the market searches also carry meta.data_captured_at.
Test searches: Ford Fiesta, Ford Focus, Ford Kuga, Vauxhall Corsa, Vauxhall Astra, Volkswagen Golf, Volkswagen Polo, BMW 3 Series, BMW 1 Series, Audi A3, Mercedes-Benz A-Class, Mercedes-Benz C-Class, Nissan Qashqai, Nissan Juke, Kia Sportage, Hyundai Tucson, Toyota Yaris, Peugeot 208, Tesla Model 3, Land Rover Range Rover Evoque.
About the data
Adverts come from UK dealer websites and are refreshed daily.
Sold is inferred: the advert ended and the same car did not reappear within 7 days. The price is the last asking price, not a confirmed sale price.
Medians and percentiles on live data are approximate. Money is in whole pounds, dates are YYYY-MM-DD.
Fields we do not hold for an advert are left out, never sent as null or a placeholder.
Ids are ours: adverts adv_..., dealers dlr_.... The same advert or dealer keeps the same id.
Personal data: dealer names, phone numbers and emails are sent as dealers publish them. For sole traders these are personal data. Use them only where you have a lawful basis, and do not store them or build a contact list from them. See the developer terms.
Errors and refunds
These endpoints answer with the version 2 error codes. Charging follows the work done: every lookup our data source answers is charged, including an advert or dealer it no longer holds (404, with error.charged: true) and a registration with no adverts (a successful answer with an empty list). A search that finds no adverts is a successful answer and is charged. So is a search the data source made and then refused because of a value or postcode it could not use (400 INVALID_PARAMETER; the error message says the search was charged). Mistakes we find in the request before searching (400), a postcode we cannot find, and a data source failure (502 or 503) are not charged.
INVALID_PARAMETER: a field is not taken by the endpoint, out of range or clashes with another; details.parameter names it
Per account across your live keys, reset at midnight UK time. The package limits on the API documentation apply as well.
Limit
Pay As You Go
Starter
Pro
Enterprise
Per second
2
5
10
20
Per minute
60
100
300
600
Per day
500
2,000
5,000
15,000
Daily cap per endpoint
Market listings
200
750
2,000
5,000
Market listings (bulk)
20
75
200
500
Sold listings search
200
750
2,000
5,000
Sold listings search (bulk)
20
75
200
500
Price drops
200
750
2,000
5,000
Market statistics
200
750
2,000
5,000
Market counts
200
750
2,000
5,000
Price and mileage bands
200
750
2,000
5,000
Market overview
200
750
2,000
5,000
One advert in full
200
750
2,000
5,000
Advert history
200
750
2,000
5,000
Live adverts for a plate
200
750
2,000
5,000
Dealer search
200
750
2,000
5,000
Dealer detail
200
750
2,000
5,000
Dealer stock
200
750
2,000
5,000
Questions
Do I need a registration to search the market?
No. /v1/market/listings, sold-listings, price-drops, stats, facets, distribution and overview search by make, model and any other filter. Only advert history and live adverts take a registration.
How do I get more than 50 results?
Each call returns up to 50 results. Send start 0, then 50, then 100 and so on, and stop when more_available is false. start plus rows can be at most 10,000. For charts and maps, bulk: true returns up to 1,000 light rows a call.
How much does a call cost?
One data request is 10p on Pay As You Go, 8p on Starter, 5p on Pro, 3p on Enterprise. The market overview makes two requests and costs twice that. Bulk mode is priced as 5 requests. Mistakes we find in the request before searching (400) and data source failures (502) are not charged. A search the data source made is charged, even when it then rejects a value or postcode (400 INVALID_PARAMETER, and the error message says the search was charged) or the advert or dealer id no longer exists (404 LISTING_NOT_FOUND or DEALER_NOT_FOUND).
What does "sold" mean?
Sold is inferred: the advert ended and the same car did not reappear within 7 days. The price is the last asking price, not a confirmed sale price.
Can I store dealer contact details?
No. Dealer names, phone numbers and emails are sent as dealers publish them. For sole traders they are personal data: use them only where you have a lawful basis and do not store them or build a contact list from them.
Can I test without paying?
Yes. Sandbox keys are free and answer from a stored sample of fictional adverts for the 20 test models listed at GET /v1/sandbox/market-presets (about 2,000 for sale and 2,000 sold). Search the whole sample or name any of its makes and models; every filter, sort, count and statistic works on the sample. Worked examples are on the Example searches page once you sign in.