This page is a complete reference for every error the CarsXE API can return. Each entry explains **why the error happened** and **how to fix it**, so you can resolve most issues without contacting support.

You can tell whether a request succeeded from the HTTP status code. Every response body also includes a `success` boolean, so you can check either one.

---

## The error envelope

All errors share the same JSON shape:

<PortableCode value={{
 language: "json",
 code: `{
    "success": false,
    "message": "Missing vin (vehicle identification number)"
  }`
}} />

<Properties>
  <Property name="success" type="boolean">
    Always <code>false</code> for errors. Successful responses return <code>true</code>.
  </Property>
  <Property name="message" type="string">
    A human-readable description of what went wrong. Messages are stable strings — you can match on them — but prefer matching on the HTTP status code where possible.
  </Property>
  <Property name="usage" type="object">
    Present only on <code>429</code> quota errors. Contains <code>current</code>, <code>limit</code>, and <code>remaining</code> so you can see exactly where you stand. See [Rate Limits & Quotas](/docs/rate-limits).
  </Property>
</Properties>

<Note>
  A few legacy v1 routes return a <code>500</code> status for validation problems (for example, a missing
  <code>make</code>/<code>model</code> on the Images API). Always check the <code>success</code> field in addition to
  the status code when working with v1 endpoints. v2 endpoints use precise status codes throughout.
</Note>

---

## Status codes

| Status | Meaning | Safe to retry? |
| --- | --- | --- |
| `200` | Success. | — |
| `202` | Accepted — an async job (e.g. [Recalls Batch](/docs/v1/recalls-batch)) was queued. Poll its status endpoint. | — |
| `400` | Bad request — a parameter is missing or invalid. | No — fix the request first. |
| `401` | Authentication failed — missing, invalid, or inactive API key. | No — fix your key or billing. |
| `403` | Forbidden — your key is blocked or your plan doesn't include this API. | No |
| `404` | Not found — no data exists for this VIN/plate, or an invalid state/country code. | No — same input returns the same result. |
| `405` | Method not allowed — e.g. `GET` sent to a `POST`-only endpoint. | No — change the HTTP method. |
| `429` | Usage quota exceeded. | Not as-is — quota errors persist until you upgrade, enable overage, or the period resets. See [Rate Limits & Quotas](/docs/rate-limits). |
| `500` | Internal server error. | Yes — once, with backoff. If persistent, contact support. |
| `502` | Upstream data provider could not be reached. | Yes — with backoff. |
| `503` | Upstream provider temporarily unavailable. | Yes — with backoff. |
| `504` | Upstream request timed out. | Yes — with backoff. |

---

## Authentication errors

| Message | Status | Why it happened | How to fix it |
| --- | --- | --- | --- |
| `Missing API key` | `401` | The request did not include the `key` parameter. | Pass your API key as the `key` query parameter on every request. See [Authentication](/docs/authentication). |
| `User with this API key was not found or the API key is disabled` | `401` | The key has a typo, was revoked, or was disabled. | Copy the key again from your [dashboard](https://api.carsxe.com/dashboard). Check for whitespace or truncation. |
| `User with this API key is not active. To activate update your billing on https://api.carsxe.com/dashboard/billing` | `401` | A payment failed or your billing is not in good standing, so API access was suspended. | Update your payment method on the [billing page](https://api.carsxe.com/dashboard/billing). Access resumes immediately after. |
| `This API key has been blocked, please contact support if you believe this is an error.` | `403` | The key was flagged for abuse. | Contact support with your account email. |
| `This API is not available for your current subscription tier. Visit https://api.carsxe.com/pricing to review upgrade options.` | `403` | Your plan does not include this endpoint. | Compare plans on the [pricing page](https://api.carsxe.com/pricing) and upgrade, or remove the call. |

---

## Validation errors

These are returned before any lookup happens, so they don't count against your quota. Fix the request and resend.

| Message | Status | How to fix it |
| --- | --- | --- |
| `Missing vin (vehicle identification number)` | `400` | Pass the `vin` parameter. |
| `Wrong VIN length, must be 17 characters` | `400` | VINs are exactly 17 characters. Strip whitespace; check for `O`/`0` and `I`/`1` transcription mistakes. |
| `Missing vehicle registration number or license plate number` | `400` | Pass the `plate` parameter. |
| `Missing 2 letter state code` | `400` | Pass `state` as a 2-letter code (e.g. `CA`). Required for US plate lookups. |
| `Invalid state or country code.` | `404` | Use ISO-style 2-letter codes. See the supported-country list on the [Plate Decoder page](/docs/v2/plate-decoder). |
| `Invalid condition. Available conditions: excellent, clean, average, rough` | `400` | The `condition` parameter on [Market Value v2](/docs/v2/market-value) accepts only those four values. |
| `Invalid mileage. Must be a number` | `400` | Pass `mileage` as digits only — no commas or units. |
| `Missing image data` | `400` | VIN OCR and Plate Recognition need an image — pass a URL or base64 string. |
| `Invalid image data format. Must be a valid URL or base64 encoded string.` | `400` | Check the URL is publicly reachable, or that the base64 payload is complete. |
| `Please supply a make and model. Visit http://api.carsxe.com/docs for more information` | `500` | The Images API requires both `make` and `model`. (Legacy route — note the 500 status.) |

The [Recalls Batch](/docs/v1/recalls-batch) endpoints have additional validation rules (VIN count, CSV size and hosting, webhook URLs) — those messages are self-describing and documented on the batch page.

---

## Data not found

A `404` with one of these messages means the request was valid, but no data exists for that vehicle. Retrying the same input returns the same result.

| Message | How to fix it |
| --- | --- |
| `No data found for this VIN` | Verify the VIN is correct. Coverage varies by market and model year. |
| `No data found for this VIN. Try a deep search by setting deepdata=1 in your request` | Retry with `deepdata=1` on the [Specifications API](/docs/v1/specifications) for an extended-source lookup. |
| `Plate searches for this country have been disabled, or No data found for this plate` | Check the plate and region. Some countries are unavailable; see the coverage list on the Plate Decoder page. |
| `No lien or theft data found for this VIN` | No records exist — for many use cases this is the answer you want. |
| `No images found` | Try a less specific query (drop `trim` or `color`). |
| `No plates detected in image` | Use a sharper, better-lit image where the plate is clearly visible. |
| `No valid VIN candidates found in the image` / `No text detected in the image` | Use a higher-resolution image of the VIN plate or windshield etching. |

<Note>
  Not-found results for VIN lookups are cached for about one day. If you believe data should exist, wait before
  retrying rather than hammering the endpoint with the same VIN.
</Note>

---

## Rate limit and quota errors

A `429` means you've used up your plan's included volume for this API:

<PortableCode value={{
 language: "json",
 code: `{
  "success": false,
  "message": "API limit exceeded for market_value (6/2026). Subscription tier: starter. Current usage: 5000, Limit: 5000.",
  "usage": {
    "current": 5000,
    "limit": 5000,
    "remaining": 0
  }
}`
}} />

See [Rate Limits & Quotas](/docs/rate-limits) for how limits work, the exact response shapes, and backoff strategies.

---

## Server and upstream errors

CarsXE aggregates data from multiple providers. When a provider fails or times out, you'll see one of these:

| Message | Status | What it means | What to do |
| --- | --- | --- | --- |
| `Internal server error` | `500` | An unhandled error on our side. | Retry once with backoff. If it persists, contact support with the endpoint, parameters, and timestamp. |
| `Unable to authenticate internal request (code CV-001). Please try again later` | `500` | An internal provider credential issue — not your request. | Retry later. Quote the `CV-001` code to support if it persists. |
| `Unable to authenticate internal request (code CV-002). Please try again later` | `500` | Same as above, for the History API. | Retry later. Quote `CV-002` to support. |
| `Could not fetch data` | `502` | The upstream provider was unreachable or returned an error. | Retry with exponential backoff. |
| `Cannot access the internet at this time` | `503` | The upstream provider is temporarily down. | Retry with backoff. |
| `Request timed out. Please try again.` | `504` | The provider didn't respond in time. | Retry with backoff — these are usually transient. |

---

## Handling errors in code

Check `response.ok` / the status code first, then branch on the category. Retry only `5xx` — a `4xx` (including quota `429`s, which persist until you upgrade or enable overage) needs a fix, not a retry:

<CodeGroup title="Error handling" tag="GET" label="/specs">

```bash
CARSXE_API_KEY="CARSXE_API_KEY"
URL="https://api.carsxe.com/specs?key=${CARSXE_API_KEY}&vin=1HGCM82633A004352"
retries=3

for attempt in $(seq 0 $retries); do
  response=$(curl -s -w "\n%{http_code}" "$URL")
  body=$(echo "$response" | sed '$d')
  status=$(echo "$response" | tail -n 1)

  if [ "$(echo "$body" | jq -r '.success')" = "true" ]; then
    echo "$body"
    exit 0
  fi

  # 4xx: fix the request (or your quota) — retrying won't help
  if [ "$status" -lt 500 ]; then
    echo "CarsXE $status: $(echo "$body" | jq -r '.message')" >&2
    exit 1
  fi

  # 5xx: exponential backoff
  if [ "$attempt" -lt "$retries" ]; then
    sleep $((2 ** attempt))
  fi
done

echo "CarsXE request failed after retries" >&2
exit 1
```

```js
async function carsxeRequest(url, { retries = 3 } = {}) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    const res = await fetch(url);
    const body = await res.json();

    if (body.success) return body;

    // 4xx: fix the request (or your quota) — retrying won't help
    if (res.status < 500) {
      throw new Error(`CarsXE ${res.status}: ${body.message}`);
    }

    // 5xx: exponential backoff
    if (attempt < retries) {
      await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
    }
  }
  throw new Error('CarsXE request failed after retries');
}
```

```python
import time
import httpx

def carsxe_request(url: str, params: dict, retries: int = 3) -> dict:
    for attempt in range(retries + 1):
        res = httpx.get(url, params=params)
        body = res.json()

        if body.get("success"):
            return body

        # 4xx: fix the request (or your quota) — retrying won't help
        if res.status_code < 500:
            raise RuntimeError(f"CarsXE {res.status_code}: {body['message']}")

        # 5xx: exponential backoff
        if attempt < retries:
            time.sleep(2 ** attempt)

    raise RuntimeError("CarsXE request failed after retries")
```

```php
<?php
use GuzzleHttp\Client;

function carsxeRequest(Client $client, string $path, array $query, int $retries = 3): array
{
    for ($attempt = 0; $attempt <= $retries; $attempt++) {
        $res = $client->get($path, ['query' => $query, 'http_errors' => false]);
        $body = json_decode((string) $res->getBody(), true);
        $status = $res->getStatusCode();

        if ($body['success'] ?? false) {
            return $body;
        }

        // 4xx: fix the request (or your quota) — retrying won't help
        if ($status < 500) {
            throw new RuntimeException("CarsXE {$status}: {$body['message']}");
        }

        // 5xx: exponential backoff
        if ($attempt < $retries) {
            sleep(2 ** $attempt);
        }
    }

    throw new RuntimeException('CarsXE request failed after retries');
}
```

```ruby
require 'json'
require 'net/http'
require 'uri'

def carsxe_request(url, retries: 3)
  uri = URI(url)

  (0..retries).each do |attempt|
    res = Net::HTTP.get_response(uri)
    body = JSON.parse(res.body)

    return body if body['success']

    # 4xx: fix the request (or your quota) — retrying won't help
    if res.code.to_i < 500
      raise "CarsXE #{res.code}: #{body['message']}"
    end

    # 5xx: exponential backoff
    sleep(2**attempt) if attempt < retries
  end

  raise 'CarsXE request failed after retries'
end
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

func carsxeRequest(url string, retries int) (map[string]any, error) {
	for attempt := 0; attempt <= retries; attempt++ {
		res, err := http.Get(url)
		if err != nil {
			return nil, err
		}
		bodyBytes, _ := io.ReadAll(res.Body)
		res.Body.Close()

		var body map[string]any
		if err := json.Unmarshal(bodyBytes, &body); err != nil {
			return nil, err
		}

		if success, _ := body["success"].(bool); success {
			return body, nil
		}

		// 4xx: fix the request (or your quota) — retrying won't help
		if res.StatusCode < 500 {
			return nil, fmt.Errorf("CarsXE %d: %v", res.StatusCode, body["message"])
		}

		// 5xx: exponential backoff
		if attempt < retries {
			time.Sleep(time.Duration(1<<attempt) * time.Second)
		}
	}

	return nil, fmt.Errorf("CarsXE request failed after retries")
}
```

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;

public class CarsxeErrorHandling {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    static Map<String, Object> carsxeRequest(String url, int retries) throws Exception {
        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

        for (int attempt = 0; attempt <= retries; attempt++) {
            HttpRequest request = HttpRequest.newBuilder(URI.create(url)).GET().build();
            HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
            Map<String, Object> body = MAPPER.readValue(res.body(), Map.class);

            if (Boolean.TRUE.equals(body.get("success"))) {
                return body;
            }

            // 4xx: fix the request (or your quota) — retrying won't help
            if (res.statusCode() < 500) {
                throw new RuntimeException("CarsXE " + res.statusCode() + ": " + body.get("message"));
            }

            // 5xx: exponential backoff
            if (attempt < retries) {
                Thread.sleep((long) Math.pow(2, attempt) * 1000);
            }
        }

        throw new RuntimeException("CarsXE request failed after retries");
    }
}
```

```swift
import Foundation

func carsxeRequest(url: URL, retries: Int = 3) async throws -> [String: Any] {
    for attempt in 0...retries {
        let (data, response) = try await URLSession.shared.data(from: url)
        guard let http = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }

        let body = try JSONSerialization.jsonObject(with: data) as? [String: Any] ?? [:]

        if body["success"] as? Bool == true {
            return body
        }

        // 4xx: fix the request (or your quota) — retrying won't help
        if http.statusCode < 500 {
            let message = body["message"] as? String ?? "Unknown error"
            throw NSError(domain: "CarsXE", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: "CarsXE \(http.statusCode): \(message)"])
        }

        // 5xx: exponential backoff
        if attempt < retries {
            try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(attempt))) * 1_000_000_000)
        }
    }

    throw NSError(domain: "CarsXE", code: -1, userInfo: [NSLocalizedDescriptionKey: "CarsXE request failed after retries"])
}
```

```csharp
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

class Program
{
    static async Task<JsonDocument> CarsxeRequest(string url, int retries = 3)
    {
        using var client = new HttpClient();

        for (int attempt = 0; attempt <= retries; attempt++)
        {
            var res = await client.GetAsync(url);
            var body = await res.Content.ReadAsStringAsync();
            using var doc = JsonDocument.Parse(body);
            var root = doc.RootElement;

            if (root.GetProperty("success").GetBoolean())
            {
                return JsonDocument.Parse(body);
            }

            // 4xx: fix the request (or your quota) — retrying won't help
            if ((int)res.StatusCode < 500)
            {
                var message = root.GetProperty("message").GetString();
                throw new Exception($"CarsXE {(int)res.StatusCode}: {message}");
            }

            // 5xx: exponential backoff
            if (attempt < retries)
            {
                await Task.Delay((int)Math.Pow(2, attempt) * 1000);
            }
        }

        throw new Exception("CarsXE request failed after retries");
    }
}
```

</CodeGroup>

---

## CORS errors

The CarsXE API is meant to be called **from your server**, never from the browser. This protects your API key from being stolen — any key shipped to a browser is public. If you call the API from frontend JavaScript, the browser will block the request with a CORS error.

Route requests through your backend instead, and keep your key in an environment variable.

---

## Still stuck?

If you've checked the tables above and the error doesn't make sense, contact support and include:

- The **endpoint** and **parameters** you sent (redact your API key)
- The **full response body** and **HTTP status code**
- The **timestamp** (with timezone) of the failing request
