Introducing the Batch Vehicle Recalls API: Check Thousands of VINs in a Single Request

batch recalls apivehicle recallsnhtsa recallsvin lookupfleet complianceinsurance underwritingdealer recall sweepcarsxe apiautomotive api
Introducing the Batch Vehicle Recalls API: Check Thousands of VINs in a Single Request

If you've ever tried to reconcile recall data across a 10,000-vehicle fleet by calling a single-VIN endpoint once per car, you know the pain. Rate limits. Throttling. Retry logic. An ops team watching a progress bar crawl forward over the course of a weekend.

Today we're fixing that.

We're launching the Batch Vehicle Recalls API — a single endpoint that accepts a list of VINs and returns the same rich recall data our customers already use, for every vehicle, in one response.

A quick refresher on the recalls endpoint

For context, our existing Vehicle Recalls API is a simple GET:

shell
curl -G https://api.carsxe.com/v1/recalls \
  -d key=CARSXE_API_KEY \
  -d vin=1C4JJXR64PW696340

You authenticate with your key as a query parameter and pass a 17-character vin. You get back a success flag, an input echo of your query, a data object with the vehicle's manufacturer / model_year / make / model / has_recalls / recall_count, and a recalls array. Each recall in that array carries the full picture: NHTSA recall ID, manufacturer recall ID, recall campaign type, recall name, affected component, recall description, risk description, stop-sale and don't-drive flags, remedy availability, the remedy text itself, parts availability, min/max labor hours, recall status (Incomplete / Completed), recall date, and expiration date. There's a timestamp on the response, plus a uuid for the vehicle record so you can reconcile responses with your own systems later.

That contract has carried our customers a long way. The thing it doesn't do well: scale.

Why we built the batch variant

When we talked to the customers using the recalls endpoint hardest, the same three workflows kept coming up:

  1. Fleet audits. A rental company doing a quarterly safety audit on 25,000 vehicles.
  2. Insurance underwriting batches. A carrier ingesting a new book of business and needing recall status on every VIN before issuing quotes.
  3. Dealership inventory sweeps. Used-car lots verifying recall compliance across hundreds of listings before they hit the floor.

In every case, the workflow looked the same: take a CSV, fan out a bunch of parallel requests against /v1/recalls, stitch the results back together, handle failures, retry the throttled ones. We did the math on how many engineering hours our customers were burning on that glue code and decided to make it a first-class endpoint.

How the batch endpoint works

The batch endpoint follows the same conventions as the single-VIN one — same authentication, same per-vehicle response shape — just lifted to operate on an array.

You POST a list of VINs. We return an array of result objects, one per VIN, each carrying the same data block (with has_recalls, recall_count, the full recalls array, and every recall field listed above) that you'd get from the single-VIN call. If a VIN can't be resolved or hits a per-VIN error, that result comes back with success: false and an error reason — but the rest of the batch still completes cleanly. No more "one bad row kills the whole job."

Here's the shape:

shell
curl -X POST https://api.carsxe.com/v1/recalls/batch \
  -H "Content-Type: application/json" \
  -d '{
    "key": "CARSXE_API_KEY",
    "vins": [
      "1C4JJXR64PW696340",
      "WBAFR7C57CC811956",
      "1HGCM82633A123456"
    ]
  }'

And the response — note that each data block is structurally identical to the single-VIN response, so any code you already wrote against /v1/recalls keeps working:

json
{
  "success": true,
  "input": {
    "key": "API_KEY",
    "vin_count": 3
  },
  "results": [
    {
      "success": true,
      "vin": "1C4JJXR64PW696340",
      "data": {
        "uuid": "d1269d6b-54a2-4bf3-8119-1c8fdb4f0563",
        "vin": "1C4JJXR64PW696340",
        "manufacturer": "FCA US LLC",
        "model_year": "2023",
        "make": "JEEP",
        "model": "Wrangler",
        "has_recalls": true,
        "recall_count": 1,
        "recalls": [
          {
            "recall_date": "2024-09-27",
            "expiration_date": null,
            "nhtsa_id": "24V720",
            "manufacturer_id": "95B",
            "recall_campaign_type": "NHTSA",
            "recall_name": "2020-2024 JL & 2022-2024 WL PHEV High Voltage Battery",
            "component": "",
            "recall_description": "2020-2024 JL & 2022-2024 WL PHEV High Voltage Battery",
            "risk_description": "In rare circumstances, a battery pack may contain cells with separator damage... A vehicle fire can result in increased risk of occupant injury and/or injury to persons outside the vehicle, as well as property damage.",
            "stop_sale": null,
            "dont_drive": null,
            "remedy_available": null,
            "recall_remedy": "FCA US will conduct a voluntary safety recall on all affected vehicles. Remedy is a software flash followed by a HV battery replacement if needed.",
            "parts_available": null,
            "labor_hours_min": null,
            "labor_hours_max": null,
            "recall_status": "Incomplete"
          }
        ]
      }
    },
    {
      "success": true,
      "vin": "WBAFR7C57CC811956",
      "data": {
        "uuid": "8a4f1b...",
        "vin": "WBAFR7C57CC811956",
        "manufacturer": "BMW",
        "model_year": "2012",
        "make": "BMW",
        "model": "650i",
        "has_recalls": false,
        "recall_count": 0,
        "recalls": []
      }
    },
    {
      "success": false,
      "vin": "1HGCM82633A123456",
      "error": "VIN_NOT_FOUND"
    }
  ],
  "timestamp": "2026-04-21T14:22:11.094Z"
}

A few details worth calling out:

  • Same per-vehicle schema. If you've already written a parser for the single-VIN data block, you can reuse it without changes. Each entry in results[].data is the exact same shape.
  • Per-VIN error handling. Bad VINs, deleted records, and lookups that fail for any reason come back as { "success": false, "vin": "...", "error": "..." } inline, so you can log them and move on without losing the rest of the batch.
  • Same authentication. Your existing key works. No new credentials, no new SDK install.
  • Top-level success. Tells you whether the batch operation succeeded (i.e. we accepted and processed the request). Per-VIN success lives on each entry.

How requests are made and processed

For typical batch sizes the request is fully synchronous — you POST, you wait a beat, you get the full response back. We dedupe lookups within the batch and reuse cached authoritative data where it's still fresh, so latency scales sub-linearly with batch size: a 500-VIN batch is much faster than 500 sequential single-VIN calls.

For large jobs, treat the response as you would a paginated query: chunk your VIN list client-side and submit batches in parallel. We'll publish guidance on the maximum recommended batch size and any async/polling patterns in the docs as the endpoint matures — for now, the synchronous flow is the supported path and it's what every launch customer is using.

The response keeps the same timestamp and success envelope as the single-VIN call, so existing logging, observability, and retry middleware should slot in without changes.

Who this is for

  • Dealerships running inventory-wide recall sweeps before cars hit the lot.
  • Insurance carriers running recall checks on new policy batches or renewals.
  • Auto-finance platforms flagging collateral risk before funding a loan.
  • Fleet operators running scheduled safety audits across thousands of vehicles.
  • Warranty services proactively notifying customers about open recalls.
  • Automotive marketplaces displaying accurate recall status on every listing.

If you're running more than a handful of recall checks a day, this endpoint is for you.

Getting started

It's live today. If you're already a CarsXE customer, your existing API key works. Read the Vehicle Recalls reference to refresh on the per-VIN data contract — the batch endpoint inherits the same fields. SDK examples in Node.js, Python, Java, PHP, Go, Ruby, Swift, and .NET are in the docs.

If you're new to CarsXE, you can get started with a free sandbox today and try it on your own fleet today.

What's next

Batch is the first step. Over the coming months we're rolling out the same pattern across other high-volume endpoints — starting with Market Value and History — so teams can run entire datasets through our APIs without writing their own queueing layer.

If there's a specific batch-style workflow you'd like us to prioritize, reply to this post or ping the team at contact@carsxe.com. The roadmap genuinely gets shaped by these conversations.

Thanks to every customer who pushed us on this one. Ship it.

— Abe