
You need to surface official US safety recalls for a vehicle when you only know its make, model, and year. By the end of this guide you will query the Vehicle API Recalls by Make and Model endpoint, parse the JSON envelope, handle empty results, and ship recall-aware features into your app with predictable performance and caching.
What the endpoint returns and when to use it
The Recalls by Make and Model endpoint returns official US-market safety recall campaigns from NHTSA, matched by make + model + year. You do not need a VIN for this lookup; pass the US-market model name exactly as NHTSA lists it.
Scope and coverage details you should depend on:
- VIN decoding works worldwide, with fullest coverage for US-market vehicles. However, this recall endpoint matches only US-market data and does not require a VIN.
- Recalls, owner complaints, and NCAP crash ratings are US-market only. They are matched by make, model, and year.
- Dutch plate lookups are from RDW open data and never include a VIN. They are unrelated to US recalls.
- This is not a vehicle history report. It does not include title, accident, or ownership history.
If you maintain dealer tools, marketplaces, fleet, insurance software, or AI agents that need trustworthy recall data, integrate this endpoint directly from vehicles-api.com.
Endpoint, method, parameters, and authentication
Base URL: https://vehicles-api.com/api/v1
Endpoint: GET /recalls
Query parameters:
- make: US-market make name (e.g., “BMW”)
- model: US-market model name (e.g., “320i”)
- year: integer model year (e.g., 2002)
Authentication:
- Header X-API-Key: YOUR_API_KEY
- Alternatively, Authorization: Bearer YOUR_API_KEY is accepted
Every response is an envelope with either:
- status: "success", source: "nhtsa", data: {...}
- status: "error", error: { code, message }
Live counts and campaigns change as NHTSA publishes updates. Your code should treat the endpoint as authoritative and refresh your cache on a schedule appropriate for your business needs.
Copy-paste cURL example
The following request retrieves recalls for the 2002 BMW 320i (US-market model name as listed by NHTSA).
curl "https://vehicles-api.com/api/v1/recalls?make=BMW&model=320i&year=2002" -H "X-API-Key: YOUR_API_KEY"
Note: No VIN is required. This is the official example; do not substitute different values when testing connectivity.
Official JSON envelope and fields you will use
This is the exact response schema and example from the documentation. In production, expect the count and recalls array to change as NHTSA issues new campaigns.
{
"status": "success",
"source": "nhtsa",
"data": {
"year": 2002,
"make": "BMW",
"model": "320i",
"coverage": "us",
"count": 1,
"recalls": [
{
"campaign": "20V018000",
"component": "AIR BAGS:FRONTAL:PASSENGER SIDE:INFLATOR MODULE",
"received": "2020-01-15",
"summary": "BMW is recalling certain 2000-2006 3 Series vehicles equipped with Takata PSAN passenger frontal air bag inflators.",
"consequence": "An inflator explosion may result in sharp metal fragments striking the driver or other occupants.",
"remedy": "Dealers will replace the passenger front air bag, free of charge."
}
]
}
}
Fields to rely on in your integration:
- status: "success" or "error". Gate your business logic on this.
- source: "nhtsa". Useful for audit and telemetry.
- data.year, data.make, data.model: Echo parameters; use for display and caching keys.
- data.coverage: "us" signals that the dataset is US-market only.
- data.count: Integer count of recall campaigns for the make/model/year.
- data.recalls: Array of recall objects:
- campaign: NHTSA campaign number; stable ID for deduplication.
- component: Affected system, normalized to NHTSA categories.
- received: ISO date string (YYYY-MM-DD) when the campaign was recorded by NHTSA.
- summary: High-level description of the issue and affected equipment.
- consequence: Safety consequences, to surface to end users.
- remedy: Official remedy text; dealers typically perform this at no charge.
Nullability: When upstream data is incomplete, fields can be null. Handle missing strings and empty arrays defensively. If there are zero campaigns, expect HTTP 200 with count = 0 and an empty recalls list.
Additional complete response examples
The structure of the envelope and fields is stable. Below are complete examples using the official sample values so you can validate parsing and serialization at multiple points in your pipeline (ingestion, cache, render). In live systems, the values will vary as authorities update the record.
End-to-end parsing test fixture A
{
"status": "success",
"source": "nhtsa",
"data": {
"year": 2002,
"make": "BMW",
"model": "320i",
"coverage": "us",
"count": 1,
"recalls": [
{
"campaign": "20V018000",
"component": "AIR BAGS:FRONTAL:PASSENGER SIDE:INFLATOR MODULE",
"received": "2020-01-15",
"summary": "BMW is recalling certain 2000-2006 3 Series vehicles equipped with Takata PSAN passenger frontal air bag inflators.",
"consequence": "An inflator explosion may result in sharp metal fragments striking the driver or other occupants.",
"remedy": "Dealers will replace the passenger front air bag, free of charge."
}
]
}
}
End-to-end parsing test fixture B
{
"status": "success",
"source": "nhtsa",
"data": {
"year": 2002,
"make": "BMW",
"model": "320i",
"coverage": "us",
"count": 1,
"recalls": [
{
"campaign": "20V018000",
"component": "AIR BAGS:FRONTAL:PASSENGER SIDE:INFLATOR MODULE",
"received": "2020-01-15",
"summary": "BMW is recalling certain 2000-2006 3 Series vehicles equipped with Takata PSAN passenger frontal air bag inflators.",
"consequence": "An inflator explosion may result in sharp metal fragments striking the driver or other occupants.",
"remedy": "Dealers will replace the passenger front air bag, free of charge."
}
]
}
}
End-to-end parsing test fixture C
{
"status": "success",
"source": "nhtsa",
"data": {
"year": 2002,
"make": "BMW",
"model": "320i",
"coverage": "us",
"count": 1,
"recalls": [
{
"campaign": "20V018000",
"component": "AIR BAGS:FRONTAL:PASSENGER SIDE:INFLATOR MODULE",
"received": "2020-01-15",
"summary": "BMW is recalling certain 2000-2006 3 Series vehicles equipped with Takata PSAN passenger frontal air bag inflators.",
"consequence": "An inflator explosion may result in sharp metal fragments striking the driver or other occupants.",
"remedy": "Dealers will replace the passenger front air bag, free of charge."
}
]
}
}
Use these as golden fixtures in tests to verify JSON decoding, data access, and UI rendering without reliance on upstream availability.
Integrate with Python
This example requests recalls for the 2002 BMW 320i and prints a compact summary. It also demonstrates safe handling of empty arrays and optional fields.
import requests
API_BASE = "https://vehicles-api.com/api/v1"
API_KEY = "YOUR_API_KEY"
def get_recalls(make: str, model: str, year: int):
url = f"{API_BASE}/recalls"
params = {"make": make, "model": model, "year": year}
headers = {"X-API-Key": API_KEY}
resp = requests.get(url, headers=headers, params=params, timeout=20)
# Do not assume HTTP status guarantees success; always check envelope.
data = resp.json()
if data.get("status") != "success":
err = data.get("error", {})
raise RuntimeError(f"Vehicle API error: {err.get('code')} - {err.get('message')}")
payload = data.get("data", {}) or {}
return payload
def summarize(payload: dict):
year = payload.get("year")
make = payload.get("make")
model = payload.get("model")
coverage = payload.get("coverage")
count = payload.get("count", 0) or 0
recalls = payload.get("recalls") or []
print(f"{year} {make} {model} — coverage: {coverage} — {count} recall(s)")
for r in recalls:
campaign = r.get("campaign") or ""
component = r.get("component") or ""
received = r.get("received") or ""
summary = r.get("summary") or ""
consequence = r.get("consequence") or ""
remedy = r.get("remedy") or ""
print(f"- {campaign} [{received}] {component}")
print(f" Summary: {summary}")
print(f" Consequence: {consequence}")
print(f" Remedy: {remedy}")
if __name__ == "__main__":
payload = get_recalls("BMW", "320i", 2002)
summarize(payload)
Use the returned data.year/make/model as your cache key and the campaign field as a stable identifier when merging or deduplicating content across data runs.
Response envelope, errors, rate limits, and quotas
All responses use a consistent envelope. Always check status before reading data:
- On success: status = "success", source = "nhtsa", data contains year/make/model/coverage/count/recalls.
- On error: status = "error", error.code and error.message describe the issue (e.g., missing parameters, authentication required, or upstream unavailability).
Rate limits and monthly quotas vary by plan. The Starter plan is $19/month and every plan includes a 7‑day free trial. For current limits and recommended retry strategies, see the Documentation.
Practical guidance:
- Do not poll excessively for static datasets. Recalls rarely change more than daily; schedule refresh jobs to respect your plan limits.
- Cache by normalized key: lowercase-trim make and model as NHTSA lists them, and use the integer year.
- Treat empty arrays as valid 200 responses. Do not retry on count = 0 unless your business logic requires periodic refresh.
Normalization, matching, and null handling
To avoid false negatives, match your vehicle inventory to NHTSA’s US-market naming. Trim spaces and control casing. For example, “320i” is not “3 Series 320i” in the query; the endpoint expects the model field as NHTSA lists it.
Expect optional strings (component, consequence, remedy) to be null on rare occasions, depending on the upstream source. Your code should coalesce null to empty strings only for display; persist nulls internally so you can detect future enrichments.
When you enrich records with VIN decoding or RDW plate data, keep those objects separate from US recall matches. VIN decoding is global and can help you derive the correct US-market model name, but the recall query itself must be make + model + year.
Caching strategy across endpoints (including VIN decoding)
For stable performance and cost control, cache aggressively where data changes slowly:
- Recalls by Make/Model/Year: Cache the full data object keyed by (make_lc, model_lc, year). Refresh on a schedule aligned to your business (e.g., daily or weekly) and on user-triggered refresh.
- VIN decoding: Cache decoded VIN payloads permanently or with a long TTL. VINs decode deterministically and rarely change; invalid or incomplete decodes should be retried only if you suspect recent updates.
When rendering a vehicle detail page, combine a cached VIN decode (to derive canonical make/model/year) with a cached recall payload. If your backend or agent stack uses tools, you can also access the same data via the MCP server: MCP.
If you’re building user-facing flows and want to quickly verify behavior end-to-end, you can run tests against the sample in this article and your staging key, then switch to live data. Keep an eye on plan limits in your dashboard at vehicles-api.com.
Designing UI and alerts from the fields
Use the following mapping from JSON to UI/logic:
- Top-level banner: If count > 0, display “Open safety recalls” with data.count as the badge number.
- List items: campaign as the identifier, component as the subtitle, received as the badge date.
- Details: summary, consequence, and remedy as the three core paragraphs. These are human-readable and suitable for end users.
If you store historical snapshots, use campaign as a primary key and treat changes to summary/consequence/remedy as upserts.
Test and deploy checklist
- Contract tests: Validate the presence and types of status, source, and data on success; and error.code, error.message on error.
- Resilience: Treat non-2xx HTTP or status="error" as non-fatal if you have cached data; serve stale with a refresh in the background.
- Observability: Log source, make/model/year, count, and campaign IDs for audit and analytics.
- Localization: received is YYYY-MM-DD; display in the user’s locale while keeping the raw ISO date for storage.
- Compliance: Render coverage="us" in admin tools so operators understand the dataset’s market scope.
FAQ
Do I need a VIN to fetch recalls?
No. This endpoint matches recalls by make, model, and year using the US-market model name as listed by NHTSA.
What does a “no recalls” result look like?
You will get HTTP 200 with status="success", count=0, and an empty recalls array. Handle that as a valid response.
Are recalls available outside the US?
No. Recalls, complaints, and NCAP crash ratings in this API are US-market only. VIN decoding is worldwide, and Dutch plate data is from RDW, but those datasets are separate from US recalls.
How should I cache results?
Cache by normalized (make, model, year). Refresh on a schedule that suits your product (e.g., daily). VIN decodes can be cached long-term since they are stable.
Where can I find rate limits and quota details?
They vary by plan. See the latest limits and examples in the Documentation.
Start integrating with a 7‑day free trial. The Starter plan is $19/month and gets you production-ready recall data matched by make, model, and year. Register and ship your first call in minutes.




