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

  1. 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.

    Developer pricing

  2. 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_REQUEST and RATE_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: 1 header 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: what changes and how to switch

Past changes

  1. 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 match without engine_size to turn it off, like transmission and body_type; match_criteria lists engine_size when 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/insights and /v1/pricing/insights are 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_days can be lower than before.
    • A search that finds no adverts is still a successful, charged answer.
  2. Fixed

    Market data: corrected fields and more listing details

    • first_seen (live) and first_listed (sold) are now the date the advert first appeared. About half used to show a later date.
    • dealer.location and dealer.postcode now 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.score is left out (interpretation: "Insufficient data") when there is no sold data, market_position.percentile is left out when there is nothing to compare with, and lowest_active_prices no 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. images holds 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, and dealer.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, and year and days_on_market on lowest_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.
  3. 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: 2 or the account setting). Version 1 answers keep their shapes until 1 February 2027.
    • Listing id is our own id (lst_ and 32 letters and digits). The same advert keeps the same id on every call.
    • On /v1/market/sold, summary is now returned_listings_summary, because it covers only the listings returned (the cheapest), and its median is the true median.
    • recommended_price_range on /v1/pricing/insights is the sold prices' lower quartile, median and upper quartile instead of the median plus or minus 5%.
    • supply_level and demand_level on /v1/pricing/insights use the same five bands as /v1/market/insights. With fewer than 5 sold cars, demand is UNKNOWN and there is no market rating.
    • Market dates are calendar dates (YYYY-MM-DD) instead of date-times.
  4. 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_stolen and stolen.insurer_theft_recorded answer for each source on its own, and stolen.police carries 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_stolen keeps 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.category and write_off.date now 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_records is listed newest first, and the new write_off.categories lists every category held.
    • Provenance: finance rows carry is_stock_funding (true for a dealer's unit stocking line), and meta.records_generated_at says 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_keepers is the highest count in the keeper history, and 0 when 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: false says when the manufacturer model data is not held.
    • Valuation: mileage_used is the mileage the figures were produced at, as the source reports it. New valued_at: the exact time of the valuation.
    • Specification: factory equipment rows carry contents, what an option pack holds.
    • Tax and MOT: co2_emissions is 0 for electric vehicles (it was left out). New vehicle.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 test mot_test_number, and odometer_result_type.
    • Sandbox: meta.data_captured_at is now sent as documented. The 46 tax and MOT answers stored in the older format were refreshed, so they carry sources, 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.
  5. Changed

    API version 2: corrected vehicle responses

    • Version 2 (the same switch as the version 2 error codes: the DP-Error-Codes header 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/decode and /v1/vehicle/tax-mot. The flat police fields move into stolen.police, and every date is YYYY-MM-DD.
    • Decode (version 2): insurance_group, acceleration_0_62_mph, import_export.import_date and tax.first_year_six_months_gbp (never filled) are gone; registration_date and date_of_manufacture are YYYY-MM-DD, and registration_date is 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) and factory_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_adjustment and the six never-filled vehicle_summary fields are gone; valuation_date and vehicle_summary.first_registered are YYYY-MM-DD.
    • The OpenAPI file describes the version 2 shapes and publishes the version 1 shapes beside them.
  6. Fixed

    Service history: mileage unit, fixed failure messages and refund wording

    • Every service record now carries mileage_unit: mi, km, or unknown when the record shows no unit. Check it before comparing mileage with MOT readings. Nothing was removed.
    • Mercedes-Benz: service record mileages were too low (miles read as kilometres). Each visit's mileage, mileage_raw and mileage_unit now 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): workshop now 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 error is now a fixed message for its error_code, the same every time. Match on error_code, not on the text.
    • The message of a request with no records, or one that failed, says the request was refunded only when refunded_pence shows the refund.
    • Documentation: workshop is usually not supplied by the manufacturer network; callbacks and service_history webhook events send fields with no value as null, while the status and start endpoints omit them.
    • Sandbox: two more registrations test the other endings, RE22MOA (no records) and RO22AXH (failed), and the SK22AOM sample report now includes a record kept in kilometres. Sandbox answers now carry meta.data_captured_at as documented.
  7. 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.
    • workshop is omitted when the manufacturer network supplied no workshop (version 1 sends the placeholder text "OEM data" or an empty string).
    • mileage is omitted when a record shows 0 and is not the delivery record, because the mileage was not recorded. mileage_raw is always sent as received.
    • Callbacks and service_history webhook events follow the version set on your account.
  8. Changed

    Sandbox service history returns a clearly marked sample report

    • Sandbox service history requests for SK22AOM now return a generic sample report: made-up records in exactly the shape of a real answer, marked with service_history.sample: true and a sample_notice. The request, polling, callbacks and fields work as before.
    • Its pdf_url opens a sample PDF headed "SAMPLE DATA - NOT A REAL VEHICLE". Live keys never receive sample data.
  9. Changed

    Clearer error codes (version 2)

    • Every error now also carries type (whose side the fault is on), retryable, charged and doc_url, plus meta.request_id and meta.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_UNAVAILABLE and SOURCE_LIMIT_REACHED. New accounts get them from the start; version 2 answers also carry legacy_code for a while.
    • Accounts that had a live key before today keep version 1 until 1 February 2027, with next_code showing the version 2 code. Switch early per request with the DP-Error-Codes: 2 header or for the whole account in the developer portal.
    • Successful answers can carry meta.warnings, for example PARAMETER_IGNORED when a field you sent was not used, or PLATE_IN_RETENTION.
  10. 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 is 503 SOURCE_LIMIT_REACHED (version 1: 502 UPSTREAM_ERROR).
  11. 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-Signature header carries t=<unix seconds>,v1=<HMAC-SHA256 of "<t>.<raw body>"> keyed with your signing secret. DP-Event-Id stays 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.
  12. 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_changed are told when the address changes.
  13. 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 the api_key variable after importing.
    • A new API reference page at /developer/reference and this changelog, with an Atom feed.
  14. Changed

    Provenance: null means "not held for this check"

    • Provenance now keeps every structured field in the answer. null means we do not hold that data point for this check, never "no".
    • false or 0 is still a real answer: the record was checked and is clear. alerts.has_alerts is null unless finance, stolen and write-off were all checked.
    • Fields provenance does not answer (keeper history, plate changes, colour, import and export, mileage) are null instead of false, 0 or an empty list. Use /v1/vehicle/decode and /v1/vehicle/tax-mot for 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_date added.
  15. 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) and dvla (the values exactly as registered). Dates are YYYY-MM-DD.
    • raw is now always an object holding the vehicle record and, when held, the model record.
  16. Added

    Service history by VIN, and shared requests

    • /v1/vehicle/service-history accepts the full 17 character vin as well as vrm. 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 200 with the records straight away.
  17. 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.
  18. 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_url when 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 answers 410 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).
  19. 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_EXCEEDED or 429 ENDPOINT_DAILY_CAP_REACHED, with Retry-After, never charged.
    • Live responses carry X-Package-Limit-*, X-Package-Remaining-Day and, for capped endpoints, X-Endpoint-Limit-Day and X-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_pence and from_plan_credit_pence while you hold some.
    • Every response, errors included, carries its request id in the X-Request-Id header and the body.
  20. Fixed

    Market endpoints: more listings, real totals, gearbox matching

    • Active and sold listings return up to rows cars (default 50, maximum 200). They could hold no more than 10 before.
    • total_found and the supply figures are market totals, with total_estimated / estimated when 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.
    • match applies only when sent, match_criteria shows what was really matched and match_not_applied lists fields that are not matched yet.
    • A registration we cannot identify is a free 404 instead of an empty, charged answer.
  21. 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.source says which source the vehicle details came from.
    • New sources block shows what each government source answered: found, not_found or unavailable.
    • No data from either source is a 404 (not charged), or a 502 when a source could not be reached (not charged, retry).
  22. 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.
  23. Fixed

    Mistyped registrations answer 400

    • A registration or VIN the source will not look up returns 400 INVALID_REQUEST and is not charged.
  24. Added

    Service history endpoint

    • New asynchronous POST /v1/vehicle/service-history with a free status endpoint GET /v1/vehicle/service-history/{request_id} and optional callback_url.
    • Sandbox keys go through the same lifecycle (202 pending, then completed about 20 seconds later) for the plates in the "Service history available" group.
    • Manufacturer coverage is published in the documentation.
  25. 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 is 404 SANDBOX_VRM_NOT_ALLOWED.
    • Sandbox responses carry meta.sandbox: true and 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 vin in place of vrm.
  26. 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 429 with Retry-After.
  27. Fixed

    Failed lookups are never charged

    • A vehicle with no data returns 404 VEHICLE_NOT_FOUND and a data source failure 502 UPSTREAM_ERROR, instead of 500. Neither is charged: the price is refunded before the response is sent.
    • Error messages never name our data sources.