API changelog
Changes to the DealerPricing Developer API, newest first. Last updated 6 November 2026.
Follow it in a feed reader: Atom feed. See also the API reference, error codes and webhooks.
Upcoming
From
New service history prices
- From 1 December 2026 (midnight UK time) the price per request will be: Pay As You Go £4.00, Starter £3.00, Pro £2.00, Enterprise £1.00.
- A request is charged at the price in force when it is accepted, and any refund gives back exactly what was charged. Searches that find no records stay refunded in full.
From
API version 2: new error codes and corrected responses
- API version 2 becomes the default for every account on 1 February 2027. It brings the new error codes, so your code can tell apart cases that share a code in version 1 (for example the different reasons behind
INVALID_REQUESTandRATE_LIMIT_EXCEEDED), and corrected responses on the vehicle, market and service history endpoints: fields that were never filled removed, and one date format. - Version 1 keeps working until then, and can still be asked for with the
DP-Error-Codes: 1header or the portal setting for 90 days after. - Switch now: send
DP-Error-Codes: 2, or choose version 2 on your developer dashboard, to test against version 2 before the cutover.
- API version 2 becomes the default for every account on 1 February 2027. It brings the new error codes, so your code can tell apart cases that share a code in version 1 (for example the different reasons behind
Past changes
- Fixed
Market data: more accurate matching
- Requests, answer shapes and prices are unchanged; you may receive different listings because matching is more accurate.
- Engine size is now matched (within 0.2 litres). The check that was meant to do this never ran, so a 1.0 and a 2.0 of the same trim could both come back. Send
matchwithoutengine_sizeto turn it off, liketransmissionandbody_type;match_criterialistsengine_sizewhen it was used. - The year searched is the registration year when the car was registered the year after it was built (adverts are filed by registration year), else the build year.
- Sold searches take their trims from recently sold adverts instead of live ones.
- Sold figures on
/v1/market/insightsand/v1/pricing/insightsare now matched like the live adverts (gearbox, body type and engine) and count sold adverts with a price only, so demand and supply describe the same cars.sold_last_90_dayscan be lower than before. - A search that finds no adverts is still a successful, charged answer.
- Fixed
Market data: corrected fields and more listing details
first_seen(live) andfirst_listed(sold) are now the date the advert first appeared. About half used to show a later date.dealer.locationanddealer.postcodenow say where the car actually is. For dealer groups they used to show the head office for every car.- No more made-up values when we hold no data:
market_rating.scoreis left out (interpretation: "Insufficient data") when there is no sold data,market_position.percentileis left out when there is nothing to compare with, andlowest_active_pricesno longer says "Unknown". - Prices and days in the insights are whole numbers. A real mileage or door count of 0 is sent instead of being left out.
imagesholds photo links only (tracking pixels are dropped). - New listing fields, sent when the advert gives them:
drivetrain,power_bhp,euro_status,ulez_compliant,owners,first_registered,write_off_category,previous_price,previous_price_date,price_change_pct,days_at_dealer, anddealer.type,dealer.latitude,dealer.longitude. Seller contact details are never sent. - New insight fields:
demand.sold_with_price,demand.fast_sale_days,demand.slow_sale_days,sold_prices.count,sold_prices.percentile_25,sold_prices.percentile_75, andyearanddays_on_marketonlowest_active_prices. - Sandbox market answers now carry
meta.data_captured_at. Each sandbox registration refreshes its stored market data on its first request after this change.
- Changed
Market data: corrected shapes in version 2
- These changes apply to version 2 answers only (the same switch as the error codes:
DP-Error-Codes: 2or the account setting). Version 1 answers keep their shapes until 1 February 2027. - Listing
idis our own id (lst_and 32 letters and digits). The same advert keeps the same id on every call. - On
/v1/market/sold,summaryis nowreturned_listings_summary, because it covers only the listings returned (the cheapest), and its median is the true median. recommended_price_rangeon/v1/pricing/insightsis the sold prices' lower quartile, median and upper quartile instead of the median plus or minus 5%.supply_levelanddemand_levelon/v1/pricing/insightsuse the same five bands as/v1/market/insights. With fewer than 5 sold cars, demand isUNKNOWNand there is no market rating.- Market dates are calendar dates (
YYYY-MM-DD) instead of date-times.
- These changes apply to version 2 answers only (the same switch as the error codes:
- Fixed
Vehicle endpoints: more data and corrected values (every account)
- Provenance, stolen: the police record and the insurer register are now shown side by side. New
stolen.police_marked_stolenandstolen.insurer_theft_recordedanswer for each source on its own, andstolen.policecarries the whole police record (date reported stolen, police force, record status, when the record was added, and the registration and VIN on it).stolen.is_stolenkeeps its meaning: at least one source holds a stolen marker. - Provenance alerts now name their source: "Police record: marked as stolen" and "Insurer register: theft record" replace the single "Vehicle reported stolen". Match on the fields, not on alert text.
- Provenance, write-offs:
write_off.categoryandwrite_off.datenow come from the most recent write-off record (latest loss date, else latest entry date). Before, they came from whichever record the register listed first.write_off_recordsis listed newest first, and the newwrite_off.categorieslists every category held. - Provenance: finance rows carry
is_stock_funding(true for a dealer's unit stocking line), andmeta.records_generated_atsays when the police, insurer and finance records were built. - Dates the source wrote as 23:00 UTC on the day before a UK midnight (for example insurer loss and entry dates) are sent as the right day. Version 1 keeps the timestamp format; version 2 sends
YYYY-MM-DD. - Decode:
previous_keepersis the highest count in the keeper history, and0when the record holds a keeper history with no changes (it was left out). New model-data fields:classification(type approval, vehicle and tax class),engine(engine code, cylinders and more),dimensions,weights(payload, train and combined weight),body(cab and wheelbase type, fuel tank, load volume),safety(Euro NCAP),warranty,ev(batteries, ranges, charge ports and charge times, motors), PS, lb-ft, km/h figures and model dates.meta.model_data_held: falsesays when the manufacturer model data is not held. - Valuation:
mileage_usedis the mileage the figures were produced at, as the source reports it. Newvalued_at: the exact time of the valuation. - Specification: factory equipment rows carry
contents, what an option pack holds. - Tax and MOT:
co2_emissionsis0for electric vehicles (it was left out). Newvehicle.has_outstanding_recall("Yes", "No" or "Unknown", exactly as the MOT history service says),month_of_first_registration,month_of_first_uk_registration,revenue_weight,real_driving_emissions,art_end_date,manufacture_date,mot_history.first_test_due_date, and per testmot_test_number, andodometer_result_type. - Sandbox:
meta.data_captured_atis now sent as documented. The 46 tax and MOT answers stored in the older format were refreshed, so they carrysources, the vehicle block (from the MOT record when the register holds none) and the new fields; the others gain the new fields at their normal 30-day refresh.
- Provenance, stolen: the police record and the insurer register are now shown side by side. New
- Changed
API version 2: corrected vehicle responses
- Version 2 (the same switch as the version 2 error codes: the
DP-Error-Codesheader or the account setting) now also corrects response shapes. Version 1 answers are unchanged apart from the fixes above. - Provenance (version 2): the groups this check never fills are gone (vehicle make, model, variant, year and colour,
registration,ownership,plate_changes,colour,import_export,scrapped,mileage); use/v1/vehicle/decodeand/v1/vehicle/tax-mot. The flat police fields move intostolen.police, and every date isYYYY-MM-DD. - Decode (version 2):
insurance_group,acceleration_0_62_mph,import_export.import_dateandtax.first_year_six_months_gbp(never filled) are gone;registration_dateanddate_of_manufactureareYYYY-MM-DD, andregistration_dateis the UK date only. - Specification (version 2): only what the specification source sends, live and sandbox alike:
vehicle(make, model, model description, year as a number) andfactory_equipment. The engine, performance, transmission, dimensions, economy, practicality, safety and insurance groups were empty on live answers; decode carries those facts. - Valuation (version 2):
condition_adjustments,mileage_adjustmentand the six never-filledvehicle_summaryfields are gone;valuation_dateandvehicle_summary.first_registeredareYYYY-MM-DD. - The OpenAPI file describes the version 2 shapes and publishes the version 1 shapes beside them.
- Version 2 (the same switch as the version 2 error codes: the
- Fixed
Service history: mileage unit, fixed failure messages and refund wording
- Every service record now carries
mileage_unit:mi,km, orunknownwhen the record shows no unit. Check it before comparingmileagewith MOT readings. Nothing was removed. - Mercedes-Benz: service record mileages were too low (miles read as kilometres). Each visit's
mileage,mileage_rawandmileage_unitnow come from the manufacturer's report; a visit that cannot be matched to it is sent without a mileage (mileage_unit: unknown) rather than a figure that may be wrong. - Mercedes-Benz (and smart):
workshopnow gives the servicing workshop's name and address as printed in the manufacturer's report, in place of the placeholder text. - A failed request's
erroris now a fixed message for itserror_code, the same every time. Match onerror_code, not on the text. - The
messageof a request with no records, or one that failed, says the request was refunded only whenrefunded_penceshows the refund. - Documentation:
workshopis usually not supplied by the manufacturer network; callbacks andservice_historywebhook events send fields with no value asnull, while the status and start endpoints omit them. - Sandbox: two more registrations test the other endings,
RE22MOA(no records) andRO22AXH(failed), and theSK22AOMsample report now includes a record kept in kilometres. Sandbox answers now carrymeta.data_captured_atas documented.
- Every service record now carries
- Changed
Service history records in error codes version 2
- Accounts on version 2 of the error codes (and requests sent with
DP-Error-Codes: 2) get two corrections in service history records. Version 1 is unchanged until it ends. workshopis omitted when the manufacturer network supplied no workshop (version 1 sends the placeholder text "OEM data" or an empty string).mileageis omitted when a record shows 0 and is not the delivery record, because the mileage was not recorded.mileage_rawis always sent as received.- Callbacks and
service_historywebhook events follow the version set on your account.
- Accounts on version 2 of the error codes (and requests sent with
- Changed
Sandbox service history returns a clearly marked sample report
- Sandbox service history requests for
SK22AOMnow return a generic sample report: made-up records in exactly the shape of a real answer, marked withservice_history.sample: trueand asample_notice. The request, polling, callbacks and fields work as before. - Its
pdf_urlopens a sample PDF headed "SAMPLE DATA - NOT A REAL VEHICLE". Live keys never receive sample data.
- Sandbox service history requests for
- Changed
Clearer error codes (version 2)
- Every error now also carries
type(whose side the fault is on),retryable,chargedanddoc_url, plusmeta.request_idandmeta.error_codes_version. Nothing was removed. - Version 2 codes give each cause its own code, for example
VIN_NOT_SUPPORTED,INVALID_VIN,VALUATION_NOT_AVAILABLE,SANDBOX_VEHICLE_NOT_AVAILABLE,SOURCE_UNAVAILABLEandSOURCE_LIMIT_REACHED. New accounts get them from the start; version 2 answers also carrylegacy_codefor a while. - Accounts that had a live key before today keep version 1 until 1 February 2027, with
next_codeshowing the version 2 code. Switch early per request with theDP-Error-Codes: 2header or for the whole account in the developer portal. - Successful answers can carry
meta.warnings, for examplePARAMETER_IGNOREDwhen a field you sent was not used, orPLATE_IN_RETENTION.
- Every error now also carries
- Fixed
Temporary source failures are now retried automatically
- When a data source we use has a brief failure, we now retry it for you before answering, within a few seconds and never at your cost: you are charged once at most, and only for a successful answer.
- A request that still fails answers
502 SOURCE_UNAVAILABLE(retryable, not charged). When a source will not answer us again until its daily reset the answer is503 SOURCE_LIMIT_REACHED(version 1:502 UPSTREAM_ERROR).
- Added
Signed callbacks and account webhooks
- Add HTTPS endpoints on the Webhooks page of the developer portal and choose events: balance low and topped up, key created and revoked, plan changed and change scheduled, subscription payment failed, service history completed and failed, daily limit reached, account email changed and API notices.
- Every event and every service history callback is signed: the
DP-Signatureheader carriest=<unix seconds>,v1=<HMAC-SHA256 of "<t>.<raw body>">keyed with your signing secret.DP-Event-Idstays the same on every retry so you can ignore duplicates. - Each event is sent as soon as it happens. Failed deliveries are retried after about 5, 15, 30, 120, 360 and 1,440 minutes. The OpenAPI file describes every event under
webhooks.
- Added
Change your developer account email
- You can change the sign-in email of your developer account on the dashboard. A verified account confirms the change from a link sent to the new address, and the old address gets a link to cancel it.
- Endpoints subscribed to
account.email_changedare told when the address changes.
- Added
OpenAPI description, Postman collection and API reference
- An OpenAPI 3.1 description of every endpoint at
/api/v1/openapi.json(also/developer/openapi.json). - A Postman collection at
/developer/postman.json. Paste your sandbox key into theapi_keyvariable after importing. - A new API reference page at
/developer/referenceand this changelog, with an Atom feed.
- An OpenAPI 3.1 description of every endpoint at
- Changed
Provenance: null means "not held for this check"
- Provenance now keeps every structured field in the answer.
nullmeans we do not hold that data point for this check, never "no". falseor0is still a real answer: the record was checked and is clear.alerts.has_alertsisnullunless finance, stolen and write-off were all checked.- Fields provenance does not answer (keeper history, plate changes, colour, import and export, mileage) are
nullinstead offalse,0or an empty list. Use/v1/vehicle/decodeand/v1/vehicle/tax-motfor them. - Insurer rows now carry the insurer, branch, code, claim number, contact number, theft indicator, loss type and removal date; finance rows carry the agreement number and term.
stolen.record_added_dateadded.
- Provenance now keeps every structured field in the answer.
- Added
Decode returns the full registration record
- New groups on
/v1/vehicle/decode:registration,keeper_history,v5c_issue_dates,plate_changes,colour_history,import_export,scrapped,tax(vehicle tax rates in pounds) anddvla(the values exactly as registered). Dates areYYYY-MM-DD. rawis now always an object holding the vehicle record and, when held, the model record.
- New groups on
- Added
Service history by VIN, and shared requests
/v1/vehicle/service-historyaccepts the full 17 charactervinas well asvrm. With both, the registration is searched and the VIN is returned in every answer.- A request for a vehicle searched in the last 10 minutes joins that search instead of starting another. When that search has already finished the answer is
200with the records straight away.
- Security
Source bookkeeping removed from answers
- Record ids, document versions, status blocks and billing details belonging to our data sources are removed from every answer, including inside
raw. Vehicle facts are unchanged.
- Record ids, document versions, status blocks and billing details belonging to our data sources are removed from every answer, including inside
- Changed
Service history: fresh searches, PDF links, refunds for no records
- Every service history request runs a fresh search; finished results are no longer reused for a new request.
- A completed request carries
pdf_urlwhen the manufacturer supplied a PDF: a signed link valid for up to 7 days. Each status call returns a new link, free. - A finished request can be read for 7 days (
readable_until); after that the status endpoint answers410 REQUEST_EXPIRED. - A search that finds no records is now refunded in full (
refunded_pence). Previously it was charged. - New service history prices from 1 December 2026 announced (see Upcoming).
- Changed
Package limits, plan credit and request ids
- Live calls count towards your package limits across all live keys, and some endpoints have a daily cap per account. Over a limit:
429 PACKAGE_LIMIT_EXCEEDEDor429 ENDPOINT_DAILY_CAP_REACHED, withRetry-After, never charged. - Live responses carry
X-Package-Limit-*,X-Package-Remaining-Dayand, for capped endpoints,X-Endpoint-Limit-DayandX-Endpoint-Remaining-Day. - A live key with no limits of its own follows its package. Daily limits reset at midnight UK time.
- Monthly packages: the fee comes back as plan credit, spent before your balance. Responses show
plan_credit_penceandfrom_plan_credit_pencewhile you hold some. - Every response, errors included, carries its request id in the
X-Request-Idheader and the body.
- Live calls count towards your package limits across all live keys, and some endpoints have a daily cap per account. Over a limit:
- Fixed
Market endpoints: more listings, real totals, gearbox matching
- Active and sold listings return up to
rowscars (default 50, maximum 200). They could hold no more than 10 before. total_foundand the supply figures are market totals, withtotal_estimated/estimatedwhen worked out from a sample.- Gearbox matching works: a manual car is no longer compared with automatics. Adverts without a price are no longer listed first.
matchapplies only when sent,match_criteriashows what was really matched andmatch_not_appliedlists fields that are not matched yet.- A registration we cannot identify is a free
404instead of an empty, charged answer.
- Active and sold listings return up to
- Fixed
Tax and MOT: vehicles without a register record
- When the vehicle register has no record (common for classic vehicles and plates on retention) the vehicle is identified from its MOT record, and
vehicle.sourcesays which source the vehicle details came from. - New
sourcesblock shows what each government source answered:found,not_foundorunavailable. - No data from either source is a
404(not charged), or a502when a source could not be reached (not charged, retry).
- When the vehicle register has no record (common for classic vehicles and plates on retention) the vehicle is identified from its MOT record, and
- Fixed
Market endpoints: body type matched by family
- Body type is compared by family against the decoded body style, so SUVs are no longer dropped from active and sold listings and the insights.
- Fixed
Mistyped registrations answer 400
- A registration or VIN the source will not look up returns
400 INVALID_REQUESTand is not charged.
- A registration or VIN the source will not look up returns
- Added
Service history endpoint
- New asynchronous
POST /v1/vehicle/service-historywith a free status endpointGET /v1/vehicle/service-history/{request_id}and optionalcallback_url. - Sandbox keys go through the same lifecycle (
202 pending, thencompletedabout 20 seconds later) for the plates in the "Service history available" group. - Manufacturer coverage is published in the documentation.
- New asynchronous
- Added
Sandbox test data set and VIN lookups
- Sandbox keys answer from a published set of test registrations covering stolen, write-off, finance, scrapped, plate change, electric and hybrid cases. The list is public at
GET /v1/sandbox/vrms; any other registration is404 SANDBOX_VRM_NOT_ALLOWED. - Sandbox responses carry
meta.sandbox: trueand a notice. Sandbox limits: 2 a second, 30 a minute and 300 a day per key, and 1,000 a day across all sandbox keys on an account. - Decode, spec, valuation and provenance accept
vinin place ofvrm.
- Sandbox keys answer from a published set of test registrations covering stolen, write-off, finance, scrapped, plate change, electric and hybrid cases. The list is public at
- Security
Hashed API keys and the /api/v1 base path
- API keys are stored hashed. A new key is shown once when it is created; afterwards only its prefix is shown.
- The documented base path is
https://www.dealerpricing.co.uk/api/v1. - Rate limits are shared across all our servers, so they are exact. A request over a limit answers
429withRetry-After.
- Fixed
Failed lookups are never charged
- A vehicle with no data returns
404 VEHICLE_NOT_FOUNDand a data source failure502 UPSTREAM_ERROR, instead of500. Neither is charged: the price is refunded before the response is sent. - Error messages never name our data sources.
- A vehicle with no data returns