RESIDUAL

API documentation

Two endpoints: a salvage market value estimate with the comparable sales behind it, and a retail (pre-loss) market value estimate. Base URL https://api.residualauto.com.

The full OpenAPI 3 schema is at api.residualauto.com/openapi.json, and interactive docs at api.residualauto.com/docs. To value a spreadsheet instead of calling the API, use bulk upload.

Authentication and usage

Send your key in the X-API-Key header on every request.

Salvage value

POST /v1/valuations — what the vehicle would realize at salvage auction, with the comparable sales behind the estimate.

curl -s https://api.residualauto.com/v1/valuations \
  -H "X-API-Key: $RESIDUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vin": "4T1B11HK5KU211111",
    "odometer": 78421,
    "primary_damage": "Front end",
    "title_group": "Salvage",
    "condition_grade": "Runs and drives"
  }'
import requests

r = requests.post(
    "https://api.residualauto.com/v1/valuations",
    headers={"X-API-Key": API_KEY},
    json={"vin": "4T1B11HK5KU211111", "odometer": 78421,
          "primary_damage": "Front end", "title_group": "Salvage"},
    timeout=30,
)
r.raise_for_status()
val = r.json()
print(val["estimate"], val["quantiles"]["p5"], val["quantiles"]["p95"])

Request rules

Request fields

FieldTypeNotes
vinstring11–17 characters
yearintRequired without a VIN
makestringRequired without a VIN, e.g. Toyota
modelstringRequired without a VIN
trimstring
odometernumberMiles. A reading implausible for the model year is set aside; see odometer_check
primary_damagestringe.g. Front end, Side, Water/flood
secondary_damagestring
title_groupstringSalvage, Clean, Non-repairable
condition_gradestringRuns and drives, Starts, Does not start
has_keysboolJSON true/false
statestringTwo-letter US state
fuel_type, drive_type, transmission, color, engine, body_style, engine_hp, displacement_l, engine_cylinders—Optional; send if known

Full value lists: GET /v1/form-vocabulary (no key needed).

Response

Example (values illustrative):

{
  "estimate": 6425.0,
  "currency": "USD",
  "quantiles": {"p5": 4410.0, "p10": 4980.0, "p25": 5720.0, "p50": 6425.0,
                "p75": 7190.0, "p90": 8210.0, "p95": 8960.0},
  "interval": {"p10": 4980.0, "p50": 6425.0, "p90": 8210.0},
  "band_calibration": {"profile": "s4_lookup3", "resolution": "exact-match",
                       "ignored_inputs": null, "ignored_note": null, …},
  "n_comparables": 15,
  "comp_window": {"oldest_sale_date": "2025-11-19", "newest_sale_date": "2026-09-10",
                  "span_days": 295, "recency_days": 313},
  "comps": [
    {"year": "2019", "make": "Toyota", "model": "Camry", "trim": "LE",
     "primary_damage": "Front end", "title_group": "Salvage", "odometer": "81250",
     "sale_date": "2026-06-18", "realized_price": 6100.0, "vin_prefix": "4T1B11HK5KU",
     "match_reason": [{"key": "model", "text": "same make & model"},
                      {"key": "damage", "text": "same damage type"}],
     "same_model_recent": true, "vehicle_class": "passenger vehicle",
     "body_type": "sedan", "similarity": 0.94}
  ],
  "subject_class": "passenger vehicle",
  "subject_body_type": "sedan",
  "input_tier": "listing-grade",
  "odometer_check": null,
  "content_tier": "report",
  "quota_note": null,
  "lookup_token": "…",
  "basis": "…", "accuracy_note": "…", "disclaimer": "…",
  "computed_at": "2026-09-28T14:03:22Z",
  "model": {"tag": "…", "trained_through": "…", "version_id": "…"}
}

Response fields

The estimate and its range

FieldMeaning
estimateThe market value estimate, USD. Equals quantiles.p50.
quantilesThe range around the estimate as seven price points, USD. p5–p95 is the wide range and p25–p75 the narrow one. How we measure explains how the ranges are measured.
intervalp10, p50, p90 from the same range. Kept for older integrations; use quantiles.
band_calibrationWhich calibration produced the range. profile names it. resolution is exact-match when your inputs matched a calibration fit for exactly those inputs, degraded when some inputs were set aside to reach one (named in ignored_inputs and ignored_note), and pooled when none matched.

The comparable sales

FieldMeaning
n_comparablesHow many comparable sales this response carries: the length of comps. A subscription or a Residual Report carries the 15 closest, fewer when fewer exist.
comp_windowWhen those sales happened: oldest_sale_date and newest_sale_date; span_days, the days between them; recency_days, the days from the oldest sale to your request.
compsThe sales themselves, in display order: your vehicle's make and model first, then the closest model year, then sales matching the damage and title you gave, then the nearest odometer reading. Each row carries the vehicle, its damage, title and odometer, sale_date and realized_price (USD).
comps[].vin_prefixThe first 11 characters of the sold vehicle's VIN, as the auction publishes it.
comps[].match_reasonWhat this sale shares with your vehicle, as a list of key (stable id, safe to branch on) and text (the wording we display). Only facts both vehicles carry are listed.
comps[].same_model_recenttrue when the sale is the same make and model with a model year within 3 of yours. null means not computed, not false.
comps[].vehicle_class, body_typeThe sold vehicle's class (passenger vehicle, motorcycle, commercial truck…) and body type (sedan, pickup, suv…).
comps[].similarityDeprecated: an ordering score whose scale changes with each model release. Use match_reason.
comp_noteSet when some listed sales are a different or unknown vehicle type.

Your vehicle and inputs

FieldMeaning
subject_class, subject_body_typeYour vehicle's class and body type, on the same scale as the comps.
input_tierlisting-grade when you sent condition_grade, otherwise identity-only.
odometer_checkSet when the odometer reading you sent is implausible for the model year (under 100 miles at 3+ years old, over 500,000, or over 100,000 a year). The estimate was made without it; note says so in a sentence.
used_caller_contextNames any accepted-but-ignored field that entered the estimate. Always null today.

Account, provenance and text

FieldMeaning
content_tierreport: the full payload, comps included. content_note is set if anything was withheld.
quota_noteSet when your account is past its monthly vehicles; the request was still answered in full.
lookup_tokenSend it back as the X-Lookup header to re-value the same vehicle with more or corrected details; every run counts as one vehicle. A different vehicle under the same token returns 409.
computed_atWhen this answer was computed, UTC. A stored copy is a snapshot as of then.
modelThe model that produced the answer: tag, trained_through (last sale date in its training data), version_id.
basisWhat the estimate is a value of: a realized salvage-auction price.
accuracy_noteWhich inputs the estimate used, in a sentence.
disclaimerThe disclaimer that goes with every estimate.

Retail value (pre-loss)

POST /v1/acv — what the vehicle would sell for at retail, undamaged. Included with Pro and Practice, and counted with the same vehicle as /v1/valuations.

curl -s https://api.residualauto.com/v1/acv \
  -H "X-API-Key: $RESIDUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"vin": "4T1B11HK5KU211111", "odometer": 78421}'

The retail estimate works from a year, make and model; it is more precise with an odometer reading, a trim or a 17-character vin. Damage and title fields are not accepted. A vehicle outside the retail data returns 422 with the reason.

FieldMeaning
estimate, quantiles, intervalAs in /v1/valuations, for the retail price.
bandsThe ranges, keyed inner (p25–p75), mid (p10–p90) and outer (p5–p95). Each has low, high, its nominal_coverage, and the measured_coverage and measured_n it was checked at.
bands.*.claim_withheldtrue when no coverage is stated for vehicles like this one: measured_coverage is then null and claim_withheld_reason says why. The range itself is still served. cell names the make-and-price group checked.
compsComparable retail sales, with n, the window_days_used they fall in, and per row the vehicle, mileage, price and sale_date. sale_basis is confirmed when the source published the sale and inferred when it's inferred from the listing ending. These are the comparable retail sales the model weighed for this estimate.
comp_noteThe comps' count and window as a sentence, or why there are none.
basis, basis_noteThe retail data the model was fit on, and a sentence stating it.
routeThe inputs the estimate rests on: head names the route, described_as states those inputs as a phrase, and not_read lists any inputs sent that the route does not use.
quota_note, computed_at, model, disclaimerAs in /v1/valuations.

Other endpoints

EndpointAuthReturns
GET /v1/form-vocabularynoneAccepted values for every text field
GET /v1/healthnoneService status and model tag
GET /v1/modelkeyModel tag, training cutoff, version id

Errors

StatusMeaning
401Missing, invalid, or revoked API key
403Retail value isn't included in your plan
409An X-Lookup token sent with a different vehicle
422No VIN or year+make+model, a make or model we don't list, an unknown field, or a vehicle the retail model can't value
429Per-minute rate limit, or two months running over your monthly vehicles
502VIN decode unavailable: retry, or send year/make/model
503Service temporarily unavailable: retry later

Pricing lists what each plan includes; the Enterprise card covers per-claim pricing and volume bands.

Terms of use

Responses are market value estimates from a statistical model, not appraisals, and every response carries the full disclaimer. Estimates and comps are licensed for your internal valuation workflows and client deliverables; bulk redistribution or resale of the underlying comp data requires a separate agreement.