Check thousands of vehicles for safety recalls in a single batch by submitting VINs and polling for results.
The Recalls Batch API allows you to submit up to 10,000 VINs in a single request for bulk recall checking. Unlike the standard Vehicle Recalls API which checks one VIN at a time, the batch API is designed for high-volume operations like fleet management, dealership inventory scans, and wholesale auction processing.
The Recalls Batch API is asynchronous: submit your VINs, poll for status (or use a webhook), then retrieve results when the job is completed or partial. VINs that are not already in CarsXE cache are queued for full batch processing; turnaround is typically 30-60 minutes depending on batch size and system load.
batchId immediately. The HTTP status is 202 Accepted when the batch is accepted.batchId until status is completed, partial, or failed (or wait for your customer webhook)./v1/recalls-batch/download.Caching: VINs that were checked recently may be served from cache. If every VIN in the batch is cached, the submit response can already show status: "completed" with full processedVins and no uploading / processing phase.
Full processing path: Uncached VINs move through uploading, then processing, while CarsXE prepares and runs the batch; results are written when processing finishes.
Send a POST request with VINs to start a batch recall check. You can provide VINs in three ways — use whichever is most convenient, or even combine them:
vinsJSON array of 17-character VIN strings.
csvInline CSV text containing VINs (one per line, or a single vin column).
csvUrlHTTPS URL to a CSV file containing VINs. Supported hosts: Google Sheets, Google Cloud Storage, AWS S3, Dropbox, Azure Blob, DigitalOcean Spaces, and Box. Google Sheets sharing links and Dropbox sharing links are auto-converted to direct download format. Max file size: 5 MB.
You can combine input methods — for example, pass some VINs in vins and a csvUrl for the rest. All VINs are merged and deduplicated before processing. The combined total must not exceed 10,000.
keyYour CarsXE API key (query parameter). Official SDKs may send the same key in the x-api-key header instead.
webhookUrlHTTPS URL for a customer webhook: CarsXE POSTs a JSON payload when the batch finishes (see Webhook notifications). Must be a valid HTTPS URL allowed by CarsXE validation rules.
Successful submission returns HTTP 202 with:
successtrue when the batch was accepted.
data.batchIdUnique identifier for your batch. Use this for status, results, and download.
data.statusuploading (batch being prepared), processing (recall check in progress), or completed if all VINs were satisfied from cache.
data.totalVinsNumber of unique VINs in the batch (after deduplication).
data.processedVinsVINs already reflected in this response (e.g. cache hits); increases again when the batch completes.
data.hitCountCount of VINs with at least one safety recall (aligned with hasRecalls on results).
data.hitRatePercentage (hitCount / processedVins) × 100 when processing is done; may be 0 on the initial 202 until completion.
data.createdAtISO 8601 timestamp when the batch was created.
data.updatedAtISO 8601 timestamp of the last job update.
curl -X POST "https://api.carsxe.com/v1/recalls-batch/submit?key=CARSXE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vins": [
"1HGBH41JXMN109186",
"5YJSA1E26HF000001",
"1C4JJXR64PW696340"
],
"webhookUrl": "https://your-server.com/webhook"
}'# Google Sheets sharing link (auto-converted to CSV export)
curl -X POST "https://api.carsxe.com/v1/recalls-batch/submit?key=CARSXE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"csvUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
}'
# AWS S3 signed URL
curl -X POST "https://api.carsxe.com/v1/recalls-batch/submit?key=CARSXE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"csvUrl": "https://my-bucket.s3.amazonaws.com/vins.csv?X-Amz-Signature=..."
}'
# Dropbox sharing link (auto-converted to direct download)
curl -X POST "https://api.carsxe.com/v1/recalls-batch/submit?key=CARSXE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"csvUrl": "https://www.dropbox.com/s/abc123/vins.csv"
}'{
"success": true,
"data": {
"batchId": "brb_mnablbn7_wvbaqv",
"status": "uploading",
"totalVins": 3,
"processedVins": 0,
"hitCount": 0,
"hitRate": 0,
"createdAt": "2026-03-24T10:00:00.000Z",
"updatedAt": "2026-03-24T10:00:00.000Z"
},
"message": "Batch submitted and queued for processing. Poll the status endpoint or wait for webhook notification."
}Poll the status endpoint to check if your batch has finished processing.
keyYour CarsXE API key.
batchIdThe batch ID returned from the submit endpoint.
| Status | Description |
|---|---|
pending | Reserved for future use; batches created through this API typically start as uploading or completed. |
uploading | Batch accepted; CarsXE is preparing the batch for processing. |
processing | Recall check in progress. Poll every 30–60 seconds. |
completed | All VINs processed. Results are ready. |
partial | Results available, but fewer VIN rows were returned than totalVins (treat as complete for retrieval). |
failed | Processing failed. See errorMessage. |
data.batchIdThe batch identifier.
data.numericBatchIdOptional numeric correlation id assigned when results are finalized.
data.statusCurrent processing status (see table above).
data.totalVinsTotal VINs submitted in this batch.
data.processedVinsNumber of VINs with rows in the merged result set.
data.hitCountVINs with at least one safety recall.
data.hitRatePercentage of processed VINs with a safety recall hit (0–100, two decimal places).
data.completedAtISO 8601 timestamp when processing finished (undefined / omitted while in progress).
data.errorMessageError details if status is failed.
curl -G "https://api.carsxe.com/v1/recalls-batch/status" \
-d key=CARSXE_API_KEY \
-d batchId=brb_mnablbn7_wvbaqv{
"success": true,
"data": {
"batchId": "brb_mnablbn7_wvbaqv",
"numericBatchId": 200426,
"status": "completed",
"totalVins": 3,
"processedVins": 3,
"hitCount": 2,
"hitRate": 66.67,
"createdAt": "2026-03-24T10:00:00.000Z",
"updatedAt": "2026-03-24T10:16:43.000Z",
"completedAt": "2026-03-24T10:16:43.000Z",
"errorMessage": null
}
}Once the batch status is completed or partial, fetch full recall rows as JSON or download CSV.
keyYour CarsXE API key.
batchIdThe batch ID returned from the submit endpoint.
Each VIN has vin, hasRecalls (true if there is at least one safety recall), recallCount, and recalls — an array of sparse objects in camelCase, mirroring CarsXE’s bulk recall row layout:
dealerName, dealerCode, batch name/date fields) are not exposed in JSON.Common keys include (when present): recallNhtsaNumber, recallOemNumber, recallTitle, recallDescription, recallRiskDescription, recallRemedyDescription, recallType, recallState, recallStatus, recallIssueDate, recallRefreshDate, severityCode, vehicleYear, vehicleMake, vehicleModel, isRemedied, optional field1–field10, etc. See the @carsxe/shared type BulkRecallBatchRow for the full schema; the API returns the trimmed BulkRecallBatchRowApi projection.
GET /v1/recalls-batch/download with the same key and batchId. Returns text/csv with a Content-Disposition filename. You can also build the URL with getBulkRecallBatchDownloadUrl (JS) or get_bulk_recall_batch_download_url (Python).
curl -G "https://api.carsxe.com/v1/recalls-batch/results" \
-d key=CARSXE_API_KEY \
-d batchId=brb_mnablbn7_wvbaqvcurl -G "https://api.carsxe.com/v1/recalls-batch/download" \
-d key=CARSXE_API_KEY \
-d batchId=brb_mnablbn7_wvbaqv \
-o recalls_brb_mnablbn7_wvbaqv.csv{
"success": true,
"data": {
"job": {
"batchId": "brb_mnablbn7_wvbaqv",
"numericBatchId": 200426,
"status": "completed",
"totalVins": 3,
"processedVins": 3,
"hitCount": 2,
"hitRate": 66.67,
"createdAt": "2026-03-24T10:00:00.000Z",
"completedAt": "2026-03-24T10:16:43.000Z"
},
"results": [
{
"vin": "1HGBH41JXMN109186",
"hasRecalls": true,
"recallCount": 1,
"recalls": [
{
"recallNhtsaNumber": "20V123000",
"vehicleMake": "Honda",
"recallTitle": "Passenger frontal air bag inflator",
"recallDescription": "Takata front passenger air bag inflator may rupture.",
"recallRiskDescription": "Rupture may cause injury from metal fragments.",
"recallRemedyDescription": "Dealers will replace the inflator, free of charge.",
"recallType": "Safety",
"recallStatus": "Open",
"recallIssueDate": "2020-03-15",
"isRemedied": false
}
]
},
{
"vin": "5YJSA1E26HF000001",
"hasRecalls": false,
"recallCount": 0,
"recalls": []
}
]
}
}If you pass webhookUrl on submit, CarsXE sends an HTTPS POST with Content-Type: application/json when the batch reaches a terminal state (completed or partial). Redirects are not followed. The request times out on CarsXE’s side after about 30 seconds — respond quickly on your server.
{
"event": "bulk_recall_batch_complete",
"batchId": "brb_mnablbn7_wvbaqv",
"status": "completed",
"totalVins": 100,
"processedVins": 100,
"hitCount": 25,
"hitRate": 25,
"downloadUrl": "https://api.carsxe.com/v1/recalls-batch/download?key=…&batchId=…",
"timestamp": "2026-03-24T10:16:43.000Z"
}The downloadUrl includes your API key in the query string so you can fetch the CSV without assembling the URL yourself. Your API key is not repeated as a separate JSON field.
import { CarsXE } from "@carsxe/sdk";
const carsxe = new CarsXE({ apiKey: "CARSXE_API_KEY" });
const submitResponse = await carsxe.submitBulkRecallBatch({
vins: [
"1HGBH41JXMN109186",
"5YJSA1E26HF000001",
"1C4JJXR64PW696340",
],
});
const batchId = submitResponse.data?.batchId;
if (!batchId) throw new Error("No batchId");
console.log(`Batch submitted: ${batchId}`);
let status;
do {
await new Promise((r) => setTimeout(r, 30_000));
status = await carsxe.getBulkRecallBatchStatus(batchId);
console.log(`Status: ${status.data?.status}`);
} while (
status.data?.status === "processing" ||
status.data?.status === "uploading"
);
if (status.data?.status === "completed" || status.data?.status === "partial") {
const results = await carsxe.getBulkRecallBatchResults(batchId);
console.log(`Processed: ${results.data?.job.processedVins} VINs`);
console.log(`Safety recall hits: ${results.data?.job.hitCount}`);
for (const result of results.data?.results ?? []) {
if (result.hasRecalls) {
console.log(`${result.vin}: ${result.recallCount} recall row(s)`);
}
}
}| Status | Error | Description |
|---|---|---|
| 400 | BULK_RECALL_BATCH_MISSING_VINS | No VINs provided. Supply vins, csv, or csvUrl. |
| 400 | BULK_RECALL_BATCH_TOO_MANY_VINS | Combined VIN count exceeds 10,000. |
| 400 | BULK_RECALL_BATCH_INVALID_VIN | One or more VINs are not 17 valid characters. |
| 400 | BULK_RECALL_BATCH_CSV_URL_INVALID | The csvUrl is not a valid HTTPS URL. |
| 400 | BULK_RECALL_BATCH_CSV_URL_HOST_NOT_ALLOWED | The csvUrl host is not allowed. |
| 400 | BULK_RECALL_BATCH_CSV_URL_TOO_LARGE | The CSV at csvUrl exceeds the size limit (5 MB). |
| 400 | BULK_RECALL_BATCH_CSV_URL_NOT_TEXT | The URL did not return a plain text CSV. |
| 400 | BULK_RECALL_BATCH_CSV_URL_HTTP_ERROR | The storage server returned an HTTP error (e.g. expired signed URL). |
| 400 | BULK_RECALL_BATCH_CSV_URL_REDIRECT_ERROR | Too many redirects or an invalid redirect when fetching csvUrl. |
| 400 | BULK_RECALL_BATCH_CSV_URL_TIMEOUT | Downloading the CSV from csvUrl timed out. |
| 400 | BULK_RECALL_BATCH_INVALID_WEBHOOK_URL | The webhookUrl is not a valid allowed HTTPS URL. |
| 401 | MISSING_API_KEY | No API key provided. |
| 401 | USER_NOT_FOUND | Invalid API key. |
| 401 | USER_NOT_ACTIVE | Account is not active. |
| 404 | BULK_RECALL_BATCH_NOT_FOUND | Batch not found or you don't have access. |
| 405 | ONLY_POST_ALLOWED | Submit endpoint requires POST. |
| 409 | BULK_RECALL_BATCH_NOT_COMPLETE | Batch still processing (results/download only). |
| 429 | (usage message) | Plan or usage limit exceeded (when usage metering applies). |
| 500 | BULK_RECALL_BATCH_STORAGE_ERROR | Internal storage or batch handoff error. Retry later. |
| 502 | BULK_RECALL_BATCH_CSV_URL_FETCH_FAILED | Server could not fetch the CSV from csvUrl. |