Vehicle Intelligence — Signals
All signals returned by GET /v1/vehicle/{registration}
All field names are camelCase. The response is structured into nested objects: summary, signals, scores, fleetFailureProfile, and fleetAdvisoryProfile. DVLA VES data refreshed every 12 hours. MOT intelligence derived from full DVSA test history and stored in the database.
Identity
registration # stringNormalised registration mark — uppercase, no spaces.
make # string | nullManufacturer in uppercase (e.g. "FORD", "MERCEDES-BENZ").
model # string | nullModel name from DVSA. DVLA VES does not return model — DVSA is the sole source.
vehicleType # string | nullVehicle body type from DVLA EU type approval category. Null until DVLA VES enrichment completes.
carvanmotorcyclebushgvtrailertractormotorhomeothercolour # string | nullPrimary colour as recorded on the V5C.
engineCapacityCc # integer | nullEngine displacement in cubic centimetres. Null for electric vehicles.
yearOfManufacture # integer | nullFour-digit manufacture year.
monthOfFirstRegistration # string | nullMonth and year of first registration. Format: YYYY-MM.
vehicleAgeYears # number | nullAge in years to one decimal place. Derived at response time. Null when enrichmentPending.
Summary
summary.*summary.buyRecommendation # string | nullDerived from vehicleRiskLevel, odometer trend, dangerous defect history, recall status, last MOT result, and how long it's been since the vehicle was last tested. avoid = confirmed clocking or a combination of serious safety flags. caution = elevated risk or a recent test failure. consider = some risk signals present without a hard flag. good = no significant flags. Null when no MOT history.
goodconsidercautionavoidsummary.vehicleRiskLevel # string | nullComposite risk band derived from scores.motRiskScore, scores.conditionScore, odometer trend, recall status, MOT result, and how long it's been since the vehicle was last tested. high = confirmed clocking or critical safety flags. medium = elevated risk signals. low = all clear. Null when no MOT history.
lowmediumhighsummary.conditionBand # string | nullBand of scores.conditionScore — overall safety and roadworthiness. Null when score is null.
goodfairpoorsummary.maintenanceBand # string | nullBand of scores.maintenanceScore — owner care relative to fleet peers. Null when score is null.
goodfairpoorsummary.mileageAnomalyRisk # string | nullhigh = possible odometer clocking detected. low = unusually high annual mileage. none = consistent readings. null = insufficient odometer data.
nonelowhighsummary.colourChangeIndicated # boolean | nullTrue when the colour on the current V5C (DVLA) differs from the colour at the last MOT (DVSA). Indicator of a post-accident respray or identity fraud. Null until both DVLA and DVSA enrichments have completed.
summary.aboveAverageAdvisories # boolean | nullTrue when this vehicle's per-test advisory rate exceeds the fleet average for its make/model/year. Null when there isn't enough benchmark data for that make/model/year, or too few MOT tests on this vehicle.
Emissions
signals.*signals.co2EmissionsGPerKm # integer | nullCO₂ in grams per kilometre from DVLA type approval record. Used for VED banding.
signals.euroEmissionStandard # string | nullEuropean emission standard (e.g. "EURO 6", "EURO 4"). Used to derive ulezCompliant.
signals.ulezCompliant # boolean | nullDerived from euroEmissionStandard + fuelType. Petrol/hybrid Euro 4+ = true. Diesel Euro 6+ = true. Electric = true. Null when standard unknown.
Tax & MOT status
signals.*signals.taxDueDate # date | nullWhen road tax expires. Null for SORN vehicles.
signals.taxDaysRemaining # integer | nullDays until tax expires. Negative = already expired. Derived at response time.
signals.vedBand # string | nullVED (road tax) band. A–M for pre-April 2017 registrations; "standard" for post-2017; "exempt" for pre-1980.
signals.vedAnnualCostGbp # integer | nullAnnual VED cost in GBP at current rates (effective April 2025). Updated annually.
signals.motExpiryDate # date | nullWhen the current MOT certificate expires.
signals.motDaysRemaining # integer | nullDays until MOT expires. Negative = already expired. Derived at response time.
signals.imminentMot # booleanTrue when the current MOT certificate expires within 30 days.
signals.markedForExport # booleanDVLA has marked this vehicle for export.
signals.v5cLastIssued # date | nullDate V5C (logbook) was last issued. Recently re-issued V5C can indicate a keeper change.
Recall
signals.*signals.hasOutstandingRecall # boolean | nullTrue when DVSA has an open safety recall against this vehicle. Null when DVSA returns "Unknown" (recall data unavailable for this make).
Odometer
signals.*signals.odometerTrend # string | nullAll recorded odometer readings checked in chronological order. Same-day retests are sorted failed-before-passed to avoid false positives from retesting. possible_clocking = any reading lower than the previous. high_mileage = average > 20,000 miles/year. low_mileage = average < 3,000 miles/year. consistent = steady increase within normal range. insufficient_data = fewer than 2 readings.
consistenthigh_mileagelow_mileagepossible_clockinginsufficient_datasignals.latestOdometerMiles # integer | nullMost recent recorded odometer reading in miles.
signals.typicalAnnualMileageMiles # integer | nullAverage annual mileage from first to last odometer reading.
signals.odometerVsFleetAverage # string | nullCompares this vehicle's typical annual mileage to the fleet average for its make/model/year. below_average suggests short trips / city driving; above_average suggests longer regular use. Null when there isn't enough benchmark data for that make/model/year.
below_averageaverageabove_averagesignals.drivetrainStressProfile.likelyDrivingPattern # string | nullInferred driving pattern from typical annual mileage. short_urban = < 5,000 mi/yr. long_distance = > 15,000 mi/yr. Null when no odometer data.
short_urbanmixedlong_distancesignals.drivetrainStressProfile.dpfRisk # string | nullDiesel vehicles only. DPF (diesel particulate filter) clogging risk. Short urban trips don't allow passive regeneration. high = < 3,000 mi/yr. elevated = < 7,000 mi/yr. low otherwise. Null for non-diesel or no data.
lowelevatedhighMOT history
signals.*signals.motPassRate # float | null0.0–1.0. Proportion of MOT tests passed over the vehicle's lifetime.
signals.totalMotTests # integerTotal number of MOT tests on record.
signals.totalMotFailures # integerNumber of tests where the vehicle failed.
signals.totalAdvisoryCount # integerTotal advisory items across all MOT tests.
signals.totalFailureItemCount # integerTotal MAJOR or DANGEROUS defect items across all tests.
signals.latestAdvisoryCount # integerAdvisory items on the most recent MOT test.
signals.latestFailureItemCount # integerMAJOR/DANGEROUS defect items on the most recent test.
signals.dangerousDefectEver # booleanTrue if any test in history contained a DANGEROUS severity defect.
signals.highFailureHistory # booleanTrue when motPassRate < 0.70.
signals.advisoryTrend # string | nullCompares average advisory count in the most recent third of tests against the oldest third. increasing = vehicle condition deteriorating over time. trendWindowTests shows the window size.
increasingstabledecreasinginsufficient_datasignals.advisoryMomentum # string | nullSame computation as advisoryTrend with inverted labels (worsening = more advisories recently, improving = fewer). Use this field for display; use advisoryTrend for numeric logic.
improvingstableworseninginsufficient_dataMOT time-series context
signals.*signals.daysSinceLastFailure # integer | nullDays since the most recent MOT failure. Null if no failure on record.
signals.failuresLast24Months # integer | nullNumber of MOT tests that ended in failure in the last 24 months.
signals.advisoriesLast3Tests # integer | nullTotal advisory items across the last 3 MOT tests.
signals.trendWindowTests # integerNumber of tests used for the advisory trend window (max(1, total_tests / 3)).
signals.firstMotDate # date | nullDate of the oldest MOT test on record.
signals.lastMotDate # date | nullDate of the most recent MOT test.
signals.firstMotDue # date | nullFor new vehicles with no MOT history: date of first MOT eligibility (3 years from first registration).
MOT defect patterns
signals.*signals.failureClusters # array<string> | nullDVSA failure text is keyword-classified into nine categories. Categories that appeared across more than one separate test are returned here. A vehicle with ["brakes", "suspension"] has had MAJOR or DANGEROUS defects in those systems on multiple separate tests.
brakessuspensiontyreslightssteeringbodyworkexhaustelectricalwiperssignals.repeatFailureCount # integer | nullTotal count of individual failure defect items whose category appeared in a prior test. Measures severity of recurrence — 6 repeat failures is worse than 1 even if both vehicles have the same failureClusters.
signals.advisoryClusters # array<string> | nullSame nine-category classification applied to advisory items across all tests (not just failed ones). These are the early-warning patterns that have not yet caused a failure. Same values as failureClusters.
brakessuspensiontyreslightssteeringbodyworkexhaustelectricalwipersComposite scores
scores.*scores.motRiskScore # float | null0.0–1.0. Lower = safer (inverted convention). Derived from last test result, lifetime pass rate, advisory trajectory, odometer integrity, dangerous defect history, outstanding recall, and imminent MOT expiry. Null when no MOT history.
scores.conditionScore # float | null0.0–1.0. Safety and roadworthiness composite. Higher = safer. Derived from pass rate, odometer integrity, dangerous defect history, recall status, advisory trend, and advisory performance vs fleet. Null when insufficient data.
scores.conditionPercentile # integer | nullNational percentile rank of this vehicle's MOT pass rate specifically (0–100), not of conditionScore itself — conditionScore blends six factors, this ranks only one of them, nationally with no make/model/year grouping. Populated by VehicleScoreWorker (weekly batch). Null until first worker run.
scores.maintenanceScore # float | null0.0–1.0 care quality vs same make/model/year fleet. 0.5 = exactly average. Null when benchmark has < 10 samples.
scores.maintenancePercentile # integer | nullNational percentile rank of this vehicle's raw advisory rate (advisories per test), not of maintenanceScore itself — unlike the score, this ignores failure rate and isn't benchmarked against the same make/model/year, just ranked against all vehicles nationally. Populated by VehicleScoreWorker (weekly batch). Null until first worker run.
scores.failureRateRatio # float | nullThis vehicle's per-test failure rate divided by fleet average for same make/model/year. 1.0 = average. Null when < 10 samples.
scores.advisoryRateRatio # float | nullSame as failureRateRatio but for advisory items.
scores.benchmarkSampleSize # integer | nullNumber of vehicles in the benchmark group for this make/model/year.
scores.avgAdvisoriesPerTestForMMY # float | nullFleet average advisory items per MOT test for this make/model/year. Use with advisoryRateRatio and summary.aboveAverageAdvisories to contextualise the raw advisory count. Null when benchmark has < 10 vehicles.
scores.avgFailuresPerTestForMMY # float | nullFleet average failure items per MOT test for this make/model/year. Null when benchmark has < 10 vehicles.
scores.offRoadLikelihoodScore # float | null0.0–1.0 likelihood the vehicle is off-road (SORN'd, scrapped, or a non-runner), based on how long it's been since the last MOT test. Higher = more likely off-road. Null when no MOT history.
scores.scoreConvention # string"0_to_1; higher_is_better except motRiskScore and offRoadLikelihoodScore". Reminder that both motRiskScore and offRoadLikelihoodScore are risk-oriented — higher = worse.
Fleet profiles
fleetFailureProfile.* / fleetAdvisoryProfile.*Mileage band for this vehicle's current odometer reading.
0–20k20k–40k40k–60k60k–80k80k–100k100k+fleetFailureProfile.sampleSize # integerNumber of MOT tests in this mileage band for this make/model/year.
Up to 3 failure categories most common at this mileage. Each item: { category, rate }, where rate is the fraction of the sampleSize MOT tests (not distinct vehicles) that had a failure in that category — e.g. rate: 0.3 means 30% of tests on same make/model/year vehicles at this mileage band flagged that category, not that 30% of those vehicles have ever failed on it. Null when no fleet data.
Up to 3 advisory categories most common at this mileage. Same structure and per-test rate definition as topFailures. Null when no fleet data.
Metadata
enrichmentPending # booleanTrue when the vehicle was not in the database and has been queued. All other fields null. Retry after Retry-After header.
schemaVersion # stringResponse schema version. Currently "1.0".
dataAsOf # stringISO 8601 datetime when the stored data was last refreshed from source APIs.
checkedAt # stringISO 8601 datetime when this request was processed.
sources # objectData source attribution. Fields: motHistory ("DVSA MOT History API"), mutableData ("DVLA Vehicle Enquiry Service (VES)"), safetyRating (Euro NCAP source, null when no NCAP match was found for this make/year).