# CarsXE Docs
> Official documentation for the CarsXE Vehicle Data API
## Documentation
URL: https://docs.carsxe.com/docs
Welcome to CarsXE API's documentation.
Task: Onboard a new CarsXE API customer through the dashboard wizard.
Steps:
1. Sign in at https://carsxe.com/signin (or create an account).
2. Complete profile, usage survey, and payment method in the dashboard onboarding modal.
3. Copy the API key from Dashboard → Profile after activation.
Recovery: Click "Check onboarding" (bottom-right on docs or dashboard in dev) while signed in.
Related: /docs/get-started#quickstart, /docs/get-started#authentication, /docs/guides/agents
Learn everything there is to know about CarsXE API and integrate CarsXE into your product.
#### Getting started
To get started, [sign in or create an account](https://carsxe.com/signin) and grab an API key, then read about how to make requests for the resources you need to access using our HTTP APIs.
## Guides
### Quickstart
Get a quick start integrating the API into your application.
### Products
Explore the full suite of vehicle data APIs available.
### Organizations
Share API access with your team using roles and organization API keys.
### Errors
Read about the different types of errors returned by the API.
### Rate Limits & Quotas
Understand monthly quotas, 429 responses, and overage billing.
### Agents & AI
Get an API key, read docs, and make calls — all from inside your AI agent.
### Agentic Payments
Let agents pay for supported CarsXE API calls on demand with x402.
---
## Get Started
URL: https://docs.carsxe.com/docs/get-started
Everything you need to start building with the CarsXE Vehicle Data API.
Task: Authenticate with a CarsXE API key and make a first successful vehicle-data request.
Related: /docs/get-started, /docs/guides/rate-limits, /docs/guides/errors, /docs/guides/agents
CarsXE is a REST API for vehicle data. Pass an API key and a VIN (or plate), get structured JSON back. No SDKs required, no complex auth — just HTTP.
## What's available
| API | What it returns |
|---|---|
| **VIN Decoder** | Make, model, year, engine, trim, standard equipment |
| **Market Value** | Retail, trade-in, and auction estimates |
| **Vehicle History** | Title events, salvage, junk, and insurance records |
| **Recalls** | Open safety recalls by VIN |
| **Plate Decoder** | VIN lookup from a license plate (50+ countries) |
| **Vehicle Images** | Photos by make, model, and year |
| **Recognition** | VIN and plate extraction from images |
| **Year Make Model** | Year/make/model vehicle search and OBD-II code decoder |
| **Lien & Theft** | Active liens and stolen vehicle status |
All endpoints use simple `GET` requests with query parameters. A handful of image/recognition endpoints use `POST` with a JSON body.
---
## Connect your AI agent
Connect your AI agent to the CarsXE documentation using Model Context Protocol (MCP). Your agent can retrieve documentation and code examples to help you build your integration.
1. Open your agent's MCP settings.
2. Add a remote MCP server with these settings:
| Setting | Value |
|---|---|
| **Name** | `CarsXE Docs` |
| **URL** | `https://docs.carsxe.com/mcp` |
| **Transport** | HTTP / Streamable HTTP |
| **Authentication** | None; no CarsXE API key required. |
3. Save and enable the server.
To verify the connection, ask your agent:
> Use CarsXE Docs to explain how to authenticate and decode a VIN, with links to the relevant documentation.
Confirm your agent uses the documentation tools and returns an explanation with links to the relevant CarsXE docs.
For vehicle-data tools, connect the separate [CarsXE API MCP](/docs/integrations/mcp). See the [agent guide](/docs/guides/agents) for more ways to use CarsXE documentation with AI agents.
---
## API Keys
Your API key lives in the [developer dashboard](https://carsxe.com/dashboard/developer). Sign in above to copy it directly, or open the dashboard to manage usage and rotate keys.
**Keep it secret.** Store your key in an environment variable — never hardcode it or commit it to source control.
```bash
# .env
CARSXE_API_KEY=your_key_here
# .gitignore
.env
.env.local
```
---
## Authentication
Every vehicle API request requires your key as the `key` query parameter — no headers, tokens, or OAuth flows.
```bash
curl "https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956"
```
That's it. A `401` means the key is missing or wrong. A `403` means your plan doesn't include that endpoint.
---
## Quickstart
Decode your first VIN — swap in your key and run it:
```bash
curl -G https://api.carsxe.com/specs \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
```js
const { data } = await axios.get("https://api.carsxe.com/specs", {
params: { key: "YOUR_API_KEY", vin: "WBAFR7C57CC811956" },
});
```
```python
import httpx
res = httpx.get("https://api.carsxe.com/specs", params={
"key": "YOUR_API_KEY",
"vin": "WBAFR7C57CC811956",
})
print(res.json())
```
```php
get("https://api.carsxe.com/specs", [
"query" => ["key" => "YOUR_API_KEY", "vin" => "WBAFR7C57CC811956"],
]);
echo $res->getBody();
```
```ruby
require "net/http"
uri = URI("https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956")
puts Net::HTTP.get(uri)
```
```go
resp, _ := http.Get("https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956")
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
```
```java
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956"))
.GET().build();
HttpResponse res = client.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
```
```swift
let url = URL(string: "https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956")!
let (data, _) = try await URLSession.shared.data(from: url)
print(String(data: data, encoding: .utf8)!)
```
```csharp
var res = await new HttpClient()
.GetStringAsync("https://api.carsxe.com/specs?key=YOUR_API_KEY&vin=WBAFR7C57CC811956");
Console.WriteLine(res);
```
A `200` with JSON vehicle specs means you're live. From here, explore the [API Reference](/api-reference) or check the [Errors](/docs/guides/errors) guide for handling failures.
---
## Guides
URL: https://docs.carsxe.com/docs/guides
Cross-cutting topics — rate limits, error handling, organizations, and AI agent integration.
Task: Direct users to the right CarsXE guide for rate limits, errors, organizations, or agent integration.
Related: /docs/guides/rate-limits, /docs/guides/errors, /docs/guides/agents
Cross-cutting guides that apply across all CarsXE API products.
---
## Agentic Payments
URL: https://docs.carsxe.com/docs/guides/agentic-payments
Let AI agents pay for supported CarsXE API calls with x402, without first creating or storing a CarsXE API key.
Task: Pay for supported CarsXE API calls with x402 without a CarsXE API key.
Auth rule: Omit the `key` query parameter. If `key` is present, normal API-key auth applies and x402 is skipped.
Steps:
1. Call the CarsXE endpoint without `key`, using the final query/body parameters.
2. Read the `402 Payment Required` response for `endpointId`, `price`, `resource`, and payment requirements.
3. Pay with an x402-compatible wallet or client for the exact price returned (never hardcode prices).
4. Retry the identical request with the x402 payment header (`X-PAYMENT` or the client-specific equivalent).
5. Return the normal CarsXE JSON response to the user.
Verification:
- Unpaid call returns `402` with payment instructions.
- Paid retry returns a successful `2xx` response with `success: true` and product JSON.
- Recalls-batch submit returns `202`; retain its one-time `data.batchToken` for status, results, and download requests.
- Paid responses may include an `X-PAYMENT-RESPONSE` header for run logs.
Recovery:
- `503` / "x402 payments are not configured" → use API-key auth via /docs/guides/agents instead.
- Paid retry returns `500` after settlement → do not pay again; retain the `X-PAYMENT-RESPONSE` value or transaction hash and contact CarsXE support.
- Keep request parameters identical between the unpaid call and paid retry.
Related: /docs/guides/agents, /docs/get-started#authentication, /api-reference
# Agentic Payments
Agentic payments let an AI agent call supported CarsXE APIs without a CarsXE API key. Instead, the agent uses an x402-compatible payment client or wallet, reads the payment requirements from the API response, pays for the request, and retries with the payment proof.
Use this when you want an agent to buy a single vehicle data lookup on demand, such as decoding a VIN, checking recalls, getting market value, or resolving a license plate.
If your request includes a CarsXE API key with `key=YOUR_API_KEY`, the API
uses normal API-key authentication. x402 is only used when no CarsXE API key
is sent.
## What to ask your agent
Give your agent a direct instruction that includes the vehicle task and tells it to use x402:
Each lookup is a paid API call. Prices are small and vary by endpoint — a VIN
decode is around **$0.15**, for example. Your agent reads the exact, current
price from the `402 Payment Required` response before paying, so it never
guesses.
```text title="VIN decode"
Read the CarsXE agentic payments docs at https://docs.carsxe.com/docs/guides/agentic-payments, then use x402 to pay for a CarsXE VIN decode for WBAFR7C57CC811956 and summarize the make, model, year, engine, and trim.
```
```text title="Recalls"
Read the CarsXE agentic payments docs at https://docs.carsxe.com/docs/guides/agentic-payments, then use x402 with CarsXE to check recalls for VIN WBAFR7C57CC811956. Show open recalls first.
```
```text title="Market value"
Read the CarsXE agentic payments docs at https://docs.carsxe.com/docs/guides/agentic-payments, then use x402 to pay for a CarsXE market value lookup for WBAFR7C57CC811956 with 50,000 miles in CA.
```
```text title="Plate decode"
Read the CarsXE agentic payments docs at https://docs.carsxe.com/docs/guides/agentic-payments, then use x402 to look up plate 7XER187 in California with CarsXE and tell me the decoded vehicle.
```
## Agent flow
An x402-capable agent should follow this flow:
1. Make the CarsXE API request without `key`.
2. Read the `402 Payment Required` response.
3. Inspect the returned payment requirements, including price, network, and resource.
4. Submit payment with an x402-compatible wallet or payment client.
5. Retry the same API request with the x402 payment header.
6. Read the normal CarsXE JSON response and answer the user.
Pricing is returned in the payment requirement and can vary by endpoint. Your agent should not hardcode prices; it should read the current requirement from the `402` response.
## Minimal HTTP shape
First, the agent calls the endpoint without a CarsXE API key:
```bash
curl -i "https://api.carsxe.com/specs?vin=WBAFR7C57CC811956"
```
The API responds with payment instructions:
```http title="Status"
HTTP/1.1 402 Payment Required
Content-Type: application/json
```
```json title="Response body"
{
"success": false,
"message": "Payment or API key required. Complete payment or authenticate with your CarsXE API key to continue. If paying programmatically, include the x402 payment header (payment-signature or x-payment) or an MPP Authorization: Payment credential. Get an API key: https://carsxe.com/dashboard/developer",
"endpointId": "specs.v1",
"price": "$0.15",
"resource": "/specs",
"apiKeyUrl": "https://carsxe.com/dashboard/developer"
}
```
After the agent pays with an x402-compatible client, it retries the same request with the payment proof header. Header names can vary by x402 client; CarsXE accepts the standard x402 payment header used by the client.
```bash
curl -i "https://api.carsxe.com/specs?vin=WBAFR7C57CC811956" \
-H "X-PAYMENT: "
```
Successful paid responses include the normal CarsXE API JSON body. The response can also include an `X-PAYMENT-RESPONSE` header that the agent may keep with its run logs.
## MPP (Machine Payments Protocol)
Unpaid 402s also include a native MPP Challenge:
```
WWW-Authenticate: Payment … method="evm", intent="charge", realm="api.carsxe.com"
```
Pay with `npx mppx` (protocol auto-selects MPP) or retry with
`Authorization: Payment `. A successful MPP retry returns
`Payment-Receipt`. Do not send an MPP credential and an x402 payment header on
the same request.
```bash
npx mppx validate https://api.carsxe.com -e GET:/specs --query vin=1HGCM82633A004352
npx mppx "https://api.carsxe.com/specs?vin=1HGCM82633A004352"
```
If a paid retry returns `500` after the payment settled, do not submit another
payment for the same request. Retain the `X-PAYMENT-RESPONSE` value or
transaction hash and contact CarsXE support so the result can be recovered or
the settlement can be refunded.
## Supported endpoints
| Product | Method | Path | Required parameters | Optional parameters |
| ------------------------- | ------ | ------------------------------- | ------------------------------------------------ | ------------------------------------------------------- |
| Vehicle Specifications | `GET` | `/specs` | `vin` | `deepdata`, `format`, `disableIntVINDecoding` |
| Market Value v1 | `GET` | `/marketvalue` | `vin` | `format` |
| Market Value v2 | `GET` | `/v2/marketvalue` | `vin` | `country`, `state`, `mileage`, `condition` |
| Vehicle History | `GET` | `/history` | `vin` | `format` |
| International VIN Decoder | `GET` | `/v1/international-vin-decoder` | `vin` | — |
| Vehicle Recalls | `GET` | `/v1/recalls` | `vin` | — |
| Vehicle Recalls Report | `GET` | `/v1/recalls-reports` | `vin` | — |
| Lien & Theft | `GET` | `/v1/lien-theft` | `vin` | — |
| Plate Decoder | `GET` | `/platedecoder` | `plate`, `state` | `format`, `country` |
| Plate Decoder v2 | `GET` | `/v2/platedecoder` | `plate`, `state` | `district`, `country`, `require_vin` |
| US-Only Plate Decoder | `GET` | `/v1/us-platedecoder` | `plate`, `state` | `decodeVIN` |
| Vehicle Images | `GET` | `/images` | `make`, `model` | `year`, `trim`, `color`, `angle`, `body`, `background` |
| Year Make Model | `GET` | `/v1/ymm` | `year`, `make`, `model` | `trim`, `allTrimOptions` |
| Vehicle Recalls by YMM | `GET` | `/v1/recalls-ymm` | `year`, `make`, `model` | — |
| Recall Campaign | `GET` | `/v1/recalls-campaigns` | `make`, `code` | — |
| OBD Codes Decoder | `GET` | `/obdcodesdecoder` | `code` or `obd_code` | — |
| Plate Image Recognition | `POST` | `/platerecognition` | JSON body with one image URL field | — |
| VIN OCR | `POST` | `/v1/vinocr` | JSON body with one image URL or image data field | — |
| Recalls Batch Submit | `POST` | `/v1/recalls-batch/submit` | JSON `vins` array | `webhookUrl` |
### Recalls Batch with x402
For x402, submit a JSON `vins` array. Duplicate VINs are normalized and charged once, and the payment requirement is the current per-VIN starter price multiplied by the unique VIN count. The `csv` and `csvUrl` request forms remain available with CarsXE API-key authentication only.
The successful `202` response includes `data.batchToken`. Keep this token secret: it is returned once and grants access only to that batch. Send it as `X-CarsXE-Batch-Token` when calling `/v1/recalls-batch/status`, `/v1/recalls-batch/results`, or `/v1/recalls-batch/download`. These follow-up calls do not require another x402 payment.
```bash
curl -G "https://api.carsxe.com/v1/recalls-batch/status" \
-d batchId=brb_mnablbn7_wvbaqv \
-H "X-CarsXE-Batch-Token: "
```
## Agent checklist
- Do not include `key` when using x402.
- Keep the request parameters identical between the unpaid request and the paid retry.
- Read the current price and network from the `402` response.
- Use the same endpoint path shown in the payment requirement.
- Return the CarsXE API result to the user after the paid retry succeeds.
---
## Agents & AI
URL: https://docs.carsxe.com/docs/guides/agents
Everything you need to use CarsXE vehicle data APIs from AI coding agents, LLMs, and automated pipelines — including browser-based onboarding, machine-readable documentation, and content negotiation.
Task: Help users integrate CarsXE with AI coding agents, LLMs, and automated pipelines.
Related: /docs/guides/agents, /docs/integrations/mcp, /docs/get-started
CarsXE is built to be agent-friendly. Whether you are a coding agent onboarding a new project, an LLM reasoning about vehicle data, or an automation pipeline calling REST endpoints, this page covers the features we ship specifically for AI and agent use cases.
---
## Browser-based agent onboarding
Getting a CarsXE API key from inside any AI agent — Claude Code, Claude Desktop, Cursor, Codex CLI, Gemini CLI, or any other coding assistant — takes just a few steps with no CLI install required. The agent directs you to a browser page, waits for you to authorize, then retrieves and stores your key automatically.
The complete machine-readable skill document for agents is available at
`https://carsxe.com/agent-onboarding/SKILL.md`. Agents that support skill discovery (such as Claude Code) will
pick this up automatically.
### Step 1 — Give your agent the onboarding skill
Pass the skill document URL to your agent so it knows exactly how to authenticate:
> "Use this skill to get a CarsXE API key: https://carsxe.com/agent-onboarding/SKILL.md"
The agent fetches the skill, generates secure session parameters, then presents you with a clickable link to open in your browser.
### Step 2 — Authorize in the browser
Click the link the agent provides. You will be taken to the CarsXE authorization page where you can sign in or create an account and approve access. No typing required — just click **Authorize**.
### Step 3 — Your agent retrieves the key
Once you click Authorize, the agent polls in the background and retrieves your API key. It stores it automatically (typically as `CARSXE_API_KEY` in your environment or project `.env` file).
### Step 4 — Start making calls
Your agent can immediately start making vehicle data calls on your behalf:
> "Decode VIN WBAFR7C57CC811956"
> "What is the market value of this vehicle with 50,000 miles?"
> "Check for any open recalls."
---
## Machine-readable documentation
Official docs live at [https://docs.carsxe.com](https://docs.carsxe.com). Prefer markdown routes, `llms.txt`, MCP, and the agent discovery spec over scraping HTML.
### Bootstrap from the discovery spec
Before implementing from these docs, fetch the agent discovery document:
```bash
curl https://docs.carsxe.com/.well-known/agent.json
# fallbacks:
curl https://docs.carsxe.com/.well-known/agent
curl https://docs.carsxe.com/api/docs?agent=spec
```
Use that JSON for the docs entry path, markdown route pattern, search endpoint, MCP endpoint, `llms.txt` routes, sitemap routes, `AGENTS.md`, `skill.md`, and feedback endpoints.
### Markdown routes (`.md`)
Append `.md` to any docs page URL for clean Markdown — fewer tokens, no layout markup:
```bash
curl https://docs.carsxe.com/docs/get-started.md
curl https://docs.carsxe.com/docs/products/specifications.md
curl https://docs.carsxe.com/docs/guides/agents.md
```
Successful markdown responses include `Link: ; rel="canonical"` so agents can cite the normal HTML docs URL.
### Content negotiation (`Accept: text/markdown`)
Send `Accept: text/markdown` (or `Signature-Agent`) on the canonical page URL to receive the same Markdown without appending `.md`:
```bash
curl -H "Accept: text/markdown" https://docs.carsxe.com/docs/get-started
curl -H "Signature-Agent: https://chatgpt.com" https://docs.carsxe.com/docs/get-started
```
| Type | Description |
| --------------- | ------------------------------------------------ |
| `text/html` | Default browser response |
| `text/markdown` | Clean Markdown — no layout, no navigation chrome |
Responses vary by `Accept` / `Signature-Agent` so caches keep HTML and Markdown separate.
### Docs MCP
Search and read these docs over Streamable HTTP MCP:
```txt
https://docs.carsxe.com/mcp
https://docs.carsxe.com/.well-known/mcp
```
(This is the **docs** MCP server for retrieving documentation. The CarsXE **API** MCP for vehicle data tools is separate — see [MCP Server](/docs/integrations/mcp).)
---
## Site index for LLMs (`llms.txt`)
CarsXE Docs exposes a machine-readable index at `https://docs.carsxe.com/llms.txt` (full corpus: `/llms-full.txt`). Page markdown also includes an `LLM index: /llms.txt` directive near the top.
```bash
curl https://docs.carsxe.com/llms.txt
curl https://docs.carsxe.com/llms-full.txt
```
The marketing/API site at `https://carsxe.com/llms.txt` remains available with live pricing context for the product homepage.
---
## Making API calls from an agent
All endpoints accept `key=YOUR_API_KEY` as a query parameter — the same environment variable the onboarding flow stores. POST endpoints also send the body as JSON with `Content-Type: application/json`.
### Vehicle Specifications (VIN Decode)
Decode a VIN and retrieve full vehicle specifications: make, model, year, engine, trim, equipment, and more. See [full reference](/api-reference/specifications/vehicle-specifications-vin-decoder).
```bash
curl -G https://api.carsxe.com/specs \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
### Market Value
Estimate retail, trade-in, and auction values for a vehicle by VIN, with optional mileage, state, and condition adjustments. See [full reference](/api-reference/market-value/vehicle-market-value-v2).
```bash
curl -G https://api.carsxe.com/v2/marketvalue \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956 \
-d mileage=50000 \
-d state=CA \
-d condition=clean
```
### Vehicle History
Retrieve a comprehensive history report including title records, junk/salvage events, and insurance information for a VIN. See [full reference](/api-reference/history/vehicle-history).
```bash
curl -G https://api.carsxe.com/history \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
### Vehicle Recalls
Check for open safety recalls associated with a VIN. See [full reference](/api-reference/recalls/vehicle-recalls).
```bash
curl -G https://api.carsxe.com/v1/recalls \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
### Lien & Theft Check
Check whether a vehicle has active liens or has been reported stolen. See [full reference](/api-reference/lien-and-theft/lien-theft-records).
```bash
curl -G https://api.carsxe.com/v1/lien-theft \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
### Ownership (Enterprise)
Resolve vehicle owners, contacts, and address residents by VIN, person, address, phone, or ZIP. See the [Ownership product guide](/docs/products/ownership) or [Ownership by VIN](/api-reference/ownership/ownership-by-vin).
```bash
curl -G https://api.carsxe.com/v1/ownership/vin \
-d key=YOUR_API_KEY \
-d vin=1FT8X3BT0BEA61538
```
### Plate Decoder
Look up a vehicle by license plate number. Supports 50+ countries. See [full reference](/api-reference/plate-decoder/license-plate-decoder-v2).
```bash
curl -G https://api.carsxe.com/v2/platedecoder \
-d key=YOUR_API_KEY \
-d plate=7XER187 \
-d country=US \
-d state=CA
```
### International VIN Decoder
Decode a non-US VIN from European, Asian, and other markets. See [full reference](/api-reference/specifications/international-vin-decoder).
```bash
curl -G https://api.carsxe.com/v1/international-vin-decoder \
-d key=YOUR_API_KEY \
-d vin=WF0MXXGBWM8R43240
```
### Vehicle Images
Retrieve vehicle photos by make, model, and year. Supports filtering by color, angle, photo type, and size. See [full reference](/api-reference/images/vehicle-images).
```bash
curl -G https://api.carsxe.com/images \
-d key=YOUR_API_KEY \
-d make=BMW \
-d model=5-Series \
-d year=2012
```
### Year / Make / Model
Look up vehicle data when you don't have a VIN — search by year, make, and model instead. See [full reference](/api-reference/year-make-model/year-make-model).
```bash
curl -G https://api.carsxe.com/v1/ymm \
-d key=YOUR_API_KEY \
-d year=2012 \
-d make=BMW \
-d model=5-Series
```
### Plate Image Recognition
Extract and decode a license plate number from an image URL. See [full reference](/api-reference/recognition/plate-image-recognition).
```bash
curl -X POST "https://api.carsxe.com/platerecognition?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://imagedelivery.net/moyiiSImjJPI_EZVxNMBBw/f49aed53-d736-4370-f3f4-97418841c800/public"}'
```
### VIN OCR
Extract a VIN from a photo of a VIN plate or dashboard sticker. See [full reference](/api-reference/recognition/vin-ocr).
```bash
curl -X POST "https://api.carsxe.com/v1/vinocr?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"image_url": "https://user-images.githubusercontent.com/5663423/30922082-64edb4fa-a3a8-11e7-873e-3fbcdce8ea3a.png"}'
```
### OBD Codes Decoder
Decode a diagnostic trouble code (DTC) from an OBD-II scanner — over 3,000 codes supported. See [full reference](/api-reference/year-make-model/obd-codes-decoder).
```bash
curl -G https://api.carsxe.com/obdcodesdecoder \
-d key=YOUR_API_KEY \
-d code=P0300
```
---
## MCP server for AI tools
For interactive AI editors and chat clients (Claude Desktop, Cursor, VS Code, Windsurf), the CarsXE MCP server is the recommended integration path — it exposes all endpoints as named tools and formats responses as Markdown automatically.
See the [MCP Quickstart Guide](/docs/integrations/mcp) for installation instructions for each editor.
---
## What's next?
- [Agent onboarding skill document](https://carsxe.com/agent-onboarding/SKILL.md) — machine-readable PKCE auth flow
- [docs.carsxe.com/llms.txt](https://docs.carsxe.com/llms.txt) — docs site index for LLMs
- [Agent discovery](https://docs.carsxe.com/.well-known/agent.json) — machine-readable route map
- [Docs MCP](https://docs.carsxe.com/mcp) — search and read docs via MCP
- [MCP Quickstart](/docs/integrations/mcp) — CarsXE API MCP for Claude, Cursor, VS Code, Windsurf
- [Claude Code Plugin](https://github.com/carsxe/carsxe-claude-plugin) — slash commands and auto-invoked skills
- [CLI Quickstart](/docs/sdks/cli) — terminal tool for agent-driven shell workflows
- [Authentication](/docs/get-started#authentication) — API key management
- [Quickstart](/docs/get-started#quickstart) — first API call walkthrough
---
## How Billing Units Work
URL: https://docs.carsxe.com/docs/guides/billing-units
How CarsXE counts billable usage — per call vs per result — and what that means for your bill.
Task: Understand how CarsXE billing units are counted for different APIs.
Related: /docs/guides/billing-units, /docs/guides/rate-limits, /docs/products/ownership, /docs/products/ymm-options, /docs/products/recalls
Most CarsXE APIs bill **per successful call**. A few bill per returned result or per item in the request. This page covers the result-based exceptions and points bulk VIN jobs to their own docs.
---
## Default: per successful call
A typical successful call (`success: true`) is billed as one call. Failed or empty lookups (`success: false`, `404 no_data`, validation `400`) are free.
This is **not** true of every endpoint:
- **Per result** — Ownership (below) and YMM Options bulk variants (below).
- **Per VIN in the request** — [Recalls Batch](/docs/products/recalls#recalls-batch) and VINs Batch. See those product docs; a 500-VIN submit is 500 units, not 1.
---
## Ownership — per returned record
All five Ownership lookups (VIN, Person, Address, Phone, ZIP) bill per **record** returned, not per request.
- Zero records → `404 no_data` → **free**.
- *N* records in the response (`owners` / `matches` / `records`) → **N billable units**.
Example: a VIN lookup that returns 3 owners bills 3 units. A ZIP page with 40 records bills 40.
See [Ownership docs](/docs/products/ownership) for details on each lookup type.
---
## YMM Options — bulk variants bill per model
Most YMM Options requests are billed per successful call, like any other API.
The exception is the **bulk variant list**: `dimension=variants` with `year` + `make` and **no `model`**. That request bills **per distinct model** in the response. `modelCount` is the billed quantity, with a **minimum of 1** even when `modelCount` is 0.
Example: 82 variant strings across 12 models → `modelCount: 12` → **12 billable units**.
See [YMM Options docs](/docs/products/ymm-options) for full parameter reference.
---
## Errors
URL: https://docs.carsxe.com/docs/guides/errors
Every error the CarsXE API returns — what it means, why it happened, and how to fix it. Includes the error envelope, status codes, and retry guidance.
Task: Interpret CarsXE API error codes and build resilient client error handling.
Related: /docs/guides/errors, /docs/get-started, /docs/guides/rate-limits
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:
Always false for errors. Successful responses return true.
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.
Present only on 429 quota errors. Contains current, limit, and remaining so you can see exactly where you stand. See [Rate Limits & Quotas](/docs/guides/rate-limits).
Retryable upstream failures include `"retryable": true` in the JSON body and a `Retry-After: 60` response header. Provider authentication failures return `500` without those retry signals and should not be retried automatically.
A few legacy v1 routes return a 500 status for validation problems (for example, a missing
make/model on the Images API). Always check the success field in addition to
the status code when working with v1 endpoints. v2 endpoints use precise status codes throughout.
---
## Status codes
| Status | Meaning | Safe to retry? |
| --- | --- | --- |
| `200` | Success. | — |
| `202` | Accepted — an async job (e.g. [Recalls Batch](/api-reference/recalls/submit-a-bulk-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/guides/rate-limits). |
| `500` | Internal server error. | Not by default — retry a transient internal error once, but do not retry provider authentication failures. |
| `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/get-started#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://carsxe.com/dashboard). Check for whitespace or truncation. |
| `User with this API key is not active. To activate update your billing on https://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://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://carsxe.com/pricing to review upgrade options.` | `403` | Your plan does not include this endpoint. | Compare plans on the [pricing page](https://carsxe.com/pricing) and upgrade, or remove the call. |
---
## Validation errors
These indicate invalid request data and don't count against your quota. Most are returned before a lookup; an upstream provider may also reject a structurally valid VIN. 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. |
| `Invalid VIN` | `400` | The VIN has 17 characters but is not valid. Check its characters and check digit before retrying. |
| `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](/api-reference/plate-decoder/license-plate-decoder-v2). |
| `Invalid condition. Available conditions: excellent, clean, average, rough` | `400` | The `condition` parameter on [Market Value v2](/api-reference/market-value/vehicle-market-value-v2) 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 https://docs.carsxe.com/docs for more information` | `500` | The Images API requires both `make` and `model`. (Legacy route — note the 500 status.) |
The [Recalls Batch](/api-reference/recalls/submit-a-bulk-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 lookup. 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](/api-reference/specifications/vehicle-specifications-vin-decoder) 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. |
| `Could not find code P9999` | Check the code for typos. Manufacturer-specific codes outside the standard OBD-II set are not in the reference table. |
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.
---
## Rate limit and quota errors
A `429` means you've used up your plan's included volume for this API:
See [Rate Limits & Quotas](/docs/guides/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. | Do not retry automatically. Quote the `CV-001` code to support. |
| `Unable to authenticate internal request (code CV-002). Please try again later` | `500` | Same as above, for the History API. | Do not retry automatically. 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` | `502` | 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:
```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
import { CarsXE } from "carsxe-api";
const carsxe = new CarsXE("YOUR_API_KEY");
async function carsxeRequest(vin, { retries = 3 } = {}) {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
return await carsxe.specs({ vin });
} catch (error) {
// 4xx: fix the request (or your quota) — retrying won't help
if (error.statusCode < 500) throw error;
// 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 asyncio
import time
from carsxe_api import CarsXE
carsxe = CarsXE("YOUR_API_KEY")
def carsxe_request(vin: str, retries: int = 3) -> dict:
for attempt in range(retries + 1):
try:
return asyncio.run(carsxe.specs({"vin": vin}))
except Exception as error:
# 4xx: fix the request (or your quota) — retrying won't help
if getattr(error, "status_code", 500) < 500:
raise
# 5xx: exponential backoff
if attempt < retries:
time.sleep(2 ** attempt)
raise RuntimeError("CarsXE request failed after retries")
```
```php
specs(["vin" => $vin]);
} catch (Exception $error) {
// 4xx: fix the request (or your quota) — retrying won't help
if ($error->getCode() < 500) {
throw $error;
}
// 5xx: exponential backoff
if ($attempt < $retries) {
sleep(2 ** $attempt);
}
}
}
throw new RuntimeException("CarsXE request failed after retries");
}
```
```ruby
require "carsxe"
carsxe = Carsxe::CarsXE.new(api_key: "YOUR_API_KEY")
def carsxe_request(carsxe, vin, retries: 3)
(0..retries).each do |attempt|
begin
return carsxe.specs("vin" => vin)
rescue => error
# 4xx: fix the request (or your quota) — retrying won't help
raise if error.respond_to?(:status_code) && error.status_code < 500
# 5xx: exponential backoff
sleep(2**attempt) if attempt < retries
end
end
raise "CarsXE request failed after retries"
end
```
```go
package main
import (
"fmt"
"time"
carsxe "github.com/carsxe/carsxe-go-package"
)
func carsxeRequest(client *carsxe.Client, vin string, retries int) (map[string]any, error) {
for attempt := 0; attempt <= retries; attempt++ {
result, err := client.Specs(map[string]string{"vin": vin})
if err == nil {
return result, nil
}
// 4xx: fix the request (or your quota) — retrying won't help
if apiErr, ok := err.(*carsxe.APIError); ok && apiErr.StatusCode < 500 {
return nil, err
}
// 5xx: exponential backoff
if attempt < retries {
time.Sleep(time.Duration(1< carsxeRequest(CarsXE carsxe, String vin, int retries) throws Exception {
for (int attempt = 0; attempt <= retries; attempt++) {
try {
Map params = new HashMap<>();
params.put("vin", vin);
return carsxe.specs(params);
} catch (CarsXEException e) {
// 4xx: fix the request (or your quota) — retrying won't help
if (e.getStatusCode() < 500) throw e;
// 5xx: exponential backoff
if (attempt < retries) {
Thread.sleep((long) Math.pow(2, attempt) * 1000);
}
}
}
throw new RuntimeException("CarsXE request failed after retries");
}
public static void main(String[] args) throws Exception {
CarsXE carsxe = new CarsXE("YOUR_API_KEY");
System.out.println(carsxeRequest(carsxe, "1HGCM82633A004352", 3));
}
}
```
```swift
import carsxe
let carsxe = CarsXE(apiKey: "YOUR_API_KEY")
func carsxeRequest(vin: String, retries: Int = 3) async throws -> [String: Any] {
for attempt in 0...retries {
do {
return try carsxe.specs(["vin": vin])
} catch let error as CarsXEError {
// 4xx: fix the request (or your quota) — retrying won't help
if error.statusCode < 500 { throw error }
// 5xx: exponential backoff
if attempt < retries {
try await Task.sleep(nanoseconds: UInt64(pow(2.0, Double(attempt))) * 1_000_000_000)
}
}
}
throw CarsXEError(statusCode: -1, message: "CarsXE request failed after retries")
}
```
```csharp
using carsxe;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static async Task> CarsxeRequest(
CarsXE carsxe, string vin, int retries = 3)
{
for (int attempt = 0; attempt <= retries; attempt++)
{
try
{
return await carsxe.Specs(new Dictionary { { "vin", vin } });
}
catch (CarsXEException ex)
{
// 4xx: fix the request (or your quota) — retrying won't help
if (ex.StatusCode < 500) throw;
// 5xx: exponential backoff
if (attempt < retries)
await Task.Delay((int)Math.Pow(2, attempt) * 1000);
}
}
throw new Exception("CarsXE request failed after retries");
}
static async Task Main(string[] args)
{
CarsXE carsxe = new CarsXE("YOUR_API_KEY");
var result = await CarsxeRequest(carsxe, "1HGCM82633A004352");
Console.WriteLine(result);
}
}
```
---
## 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
## Insufficient prepaid credits (HTTP 402)
A prepaid account must have enough subscription and purchased credits combined to
cover the full request. A positive balance can still be insufficient. Overage
availability does not allow the wallet to go negative.
```json
{
"success": false,
"code": "insufficient_credits",
"message": "Insufficient credits. Add credits or enable auto-recharge to continue.",
"billingUrl": "https://carsxe.com/dashboard/billing",
"credits": { "available": 2, "cost": 5, "remaining": 0, "shortfall": 3 }
}
```
Open Billing to replenish credits. Plans that do not support credit purchases
require an upgrade or assistance from support. `remaining` preserves the existing
projected balance field; a rejected request does not spend the `available` credits.
If an authorized auto-recharge is still being processed, the API returns HTTP 503:
```json
{
"success": false,
"code": "auto_recharge_pending",
"message": "Auto-recharge is pending. Retry shortly after credits are confirmed."
}
```
Retry with backoff and the same idempotency key. Do not start a second payment
because of this response. Successful API response formats are unchanged.
VIN ownership batches check the wallet before submission and charge the exact
owner-record count before publishing each paid VIN result. If other requests
consume the balance while the batch runs, affected VIN results contain
`code: "insufficient_credits"`, the credit shortfall, and no owner data. Top up
and resubmit those VINs. Legacy postpaid billing remains unchanged.
## Low-balance alerts
Prepaid accounts can configure a USD alert threshold in Billing → Credits
(default $10). The value is an approximate top-up value of all remaining credits,
not a cash balance. Eligible accounts receive dashboard warnings and one
low-balance and one empty-balance email per depletion cycle. A balance above the
configured threshold starts a new cycle. Healthy auto-recharge suppresses these
warnings; failed auto-recharge does not.
---
## Latency & Regions
URL: https://docs.carsxe.com/docs/guides/latency-and-regions
Cut transatlantic latency from Europe by calling the EU deployment — the eu-api.carsxe.com hostname, the /eu path prefix, and which endpoints are available in each region.
Task: Route CarsXE requests from Europe to the EU deployment instead of the US region.
Prerequisites:
- A valid CarsXE API key.
- A client that can change the request hostname or path prefix.
- An internationally available endpoint (plate decoder, recognition, international VIN decoder, VIN OCR, or images).
Outcome: A request from Europe uses `eu-api.carsxe.com` or the `/eu` path prefix, returns the same JSON shape as the US form, and a US-only path on the EU hostname returns `404`.
Verification:
- `GET https://eu-api.carsxe.com/v1/international-vin-decoder` with a valid key and VIN returns a successful JSON body with the same fields as the US host.
- `GET https://api.carsxe.com/eu/v1/international-vin-decoder` with the same parameters also succeeds.
- `GET https://eu-api.carsxe.com/specs` (or another US-only path) returns `404`.
Related: /docs/guides/latency-and-regions, /docs/guides/supported-countries, /docs/products/international-vin-decoder
The CarsXE API is hosted in the United States (Iowa, `us-central1`). For customers based in the US this is already low-latency. For customers in Europe, every request would otherwise pay a transatlantic round-trip on top of the actual processing time — typically 80–150 ms before the request even reaches our servers.
This page describes how to keep that overhead off your hot path.
## Use the EU endpoint from Europe
Internationally relevant endpoints — the photo-based recognition APIs, the multi-country plate decoder, and the international VIN decoder — are also deployed in `europe-west1` (Belgium). There are two equivalent ways to reach that deployment; pick whichever is easier to configure in your client.
| Form | Example | Notes |
|---|---|---|
| Regional hostname | `https://eu-api.carsxe.com/v1/international-vin-decoder` | Swap the hostname, keep the path. Easiest when your HTTP client is configured with a base URL. |
| `/eu` path prefix | `https://api.carsxe.com/eu/v1/international-vin-decoder` | Keep the hostname, prefix the path. Easiest when your client hardcodes the host. |
Both forms execute in `europe-west1` against an EU-local cache replica. Parameters, response shapes, authentication, and billing are identical to the US form.
## eu-api.carsxe.com (regional hostname)
Swap the hostname; keep the path identical to the US form. The EU hostname terminates in GCP `europe-west1` and proxies straight to the EU function deployment.
```bash
curl -G https://eu-api.carsxe.com/v1/international-vin-decoder \
-d key=YOUR_API_KEY \
-d vin=WF0MXXGBWM8R43240
```
```js
const { data } = await axios.get("https://eu-api.carsxe.com/v1/international-vin-decoder", {
params: { key: apiKey, vin },
});
```
```python
import httpx
params = {
"key": "YOUR_API_KEY",
"vin": "WF0MXXGBWM8R43240",
}
with httpx.Client(base_url="https://eu-api.carsxe.com", timeout=30.0) as client:
response = client.get("/v1/international-vin-decoder", params=params)
response.raise_for_status()
data = response.json()
```
```php
'https://eu-api.carsxe.com',
'timeout' => 30,
]);
$response = $client->get('/v1/international-vin-decoder', [
'query' => [
'key' => 'YOUR_API_KEY',
'vin' => 'WF0MXXGBWM8R43240',
],
]);
$data = json_decode($response->getBody()->getContents(), true);
```
```ruby
require 'json'
require 'net/http'
require 'uri'
uri = URI('https://eu-api.carsxe.com/v1/international-vin-decoder')
uri.query = URI.encode_www_form(
key: 'YOUR_API_KEY',
vin: 'WF0MXXGBWM8R43240'
)
response = Net::HTTP.get_response(uri)
data = JSON.parse(response.body)
```
```go
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
func main() {
params := url.Values{}
params.Set("key", "YOUR_API_KEY")
params.Set("vin", "WF0MXXGBWM8R43240")
endpoint := "https://eu-api.carsxe.com/v1/international-vin-decoder?" + params.Encode()
resp, err := http.Get(endpoint)
if err != nil {
panic(err)
}
defer resp.Body.Close()
var data map[string]any
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
panic(err)
}
fmt.Println(data)
}
```
```java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
String query = "key=" + URLEncoder.encode("YOUR_API_KEY", StandardCharsets.UTF_8)
+ "&vin=" + URLEncoder.encode("WF0MXXGBWM8R43240", StandardCharsets.UTF_8);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://eu-api.carsxe.com/v1/international-vin-decoder?" + query))
.GET()
.build();
HttpResponse response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
```
```swift
import Foundation
var components = URLComponents(string: "https://eu-api.carsxe.com/v1/international-vin-decoder")!
components.queryItems = [
URLQueryItem(name: "key", value: "YOUR_API_KEY"),
URLQueryItem(name: "vin", value: "WF0MXXGBWM8R43240"),
]
let (data, _) = try await URLSession.shared.data(from: components.url!)
let result = try JSONSerialization.jsonObject(with: data)
```
```csharp
using System.Net.Http.Json;
using HttpClient client = new()
{
BaseAddress = new Uri("https://eu-api.carsxe.com")
};
var url = $"/v1/international-vin-decoder?key={Uri.EscapeDataString("YOUR_API_KEY")}&vin={Uri.EscapeDataString("WF0MXXGBWM8R43240")}";
var data = await client.GetFromJsonAsync
## /eu path prefix
Keep `api.carsxe.com` and prefix the endpoint path with `/eu`. Useful when the host is baked into your client or SDK configuration and only the path is easy to change.
```bash
curl -G https://api.carsxe.com/eu/v1/international-vin-decoder \
-d key=YOUR_API_KEY \
-d vin=WF0MXXGBWM8R43240
```
The prefix applies to the endpoint path only — `key`, all other query parameters, and the response body are unchanged.
## Endpoints available in EU
The EU deployment covers the APIs whose data is meaningful outside the US:
- `/platedecoder`, `/v2/platedecoder` — multi-country plate decoder
- `/platerecognition` — plate recognition from photos
- `/v1/international-vin-decoder` — non-US VIN decoder
- `/v1/vinocr` — VIN OCR from photos
- `/images` — vehicle image search
Other product endpoints (`/specs`, `/marketvalue`, `/v1/recalls`, `/history`, `/v1/lien-theft`, `/v1/ymm`,
`/obdcodesdecoder`, etc.) are US-only — call them on `https://api.carsxe.com/...` without the `/eu` prefix.
Requesting a US-only path on `eu-api.carsxe.com` returns `404`.
---
## Organizations
URL: https://docs.carsxe.com/docs/guides/organizations
Organizations let you share CarsXE API access with your team. Invite members, assign roles, and manage organization-wide API keys from a single workspace.
Task: Manage CarsXE organizations, members, and API keys for team access.
Related: /docs/guides/organizations, /docs/get-started#authentication
Organizations are shared workspaces that let you collaborate with your team on CarsXE. Instead of every teammate managing their own account and API key, an organization gives you a single place to invite members, control what they can do with roles, and manage **organization API keys** that everyone can use.
You manage organizations from your [dashboard](https://carsxe.com/dashboard). No separate API is required.
Billing is **not** organization-specific. Usage from organization API keys rolls up to the
organization owner's personal subscription. There is no separate per-organization plan or invoice.
## Key concepts
### Roles & permissions
Owner, admin, editor, and viewer roles control what each member can do.
### Team & invitations
Invite teammates by email. Invitations expire after 7 days.
### Organization API keys
Shared keys that authenticate API requests for the whole team.
### Billing
Organization usage is billed to the owner's personal subscription.
## Roles and permissions
Every member of an organization has one of four roles. The **owner** is the user who created the organization and cannot be removed. All other members are assigned one of the remaining roles.
| Capability | Owner | Admin | Editor | Viewer |
| --- | :---: | :---: | :---: | :---: |
| View team & API keys | Yes | Yes | Yes | Yes |
| Create API keys | Yes | Yes | Yes | No |
| Enable/disable & rename API keys | Yes | Yes | Yes | No |
| Delete API keys | Yes | Yes | No | No |
| Invite members | Yes | Yes | No | No |
| Update member roles & remove members | Yes | Yes | No | No |
| Invite, promote, or manage admins | Yes | No | No | No |
| Edit organization settings | Yes | No | No | No |
| Delete the organization | Yes | No | No | No |
Admins can manage editors and viewers, but only the owner can invite, promote, or manage other
admins. The owner cannot be removed or have their role changed.
## Team and invitations
Owners and admins can invite teammates to the organization by email, one at a time or in bulk. Each invitation is sent with the role you choose for the invitee.
- **Expiry** — Invitations expire 7 days after they are sent.
- **Accepting** — The invitee receives an email with a link to accept. They must sign in (or create an account) with the invited email address to join.
- **Pending & failed invites** — The team view lists active members alongside any pending or failed invitations so you can resend them.
- **Removing members** — Owners and admins can remove members at any time. Removing a member immediately revokes their access to the organization.
## Organization API keys
Organization API keys work exactly like personal API keys when calling the CarsXE API — you pass them as the `key` parameter on any endpoint. The difference is that an organization key belongs to the workspace, so any current member can use it and key management is shared across the team.
- **Shared access** — Any member can use an organization key to make API requests, subject to their role's permissions for managing keys.
- **Usage tracking** — Each key tracks lifetime usage and monthly usage broken down by API type.
- **Status** — A key is active only while the organization owner's subscription is active. If the owner's subscription becomes inactive, the organization's keys stop working until it is reactivated.
Use an organization API key the same way you use any CarsXE key:
```bash
curl https://api.carsxe.com/v1/auth/validate \
-d key=ORGANIZATION_API_KEY
```
See [Authentication](/docs/get-started#authentication) for more on how API keys authenticate your requests.
## Billing
Organizations are a collaboration and access-management layer — they are not a billing entity. When a request is made with an organization API key, the usage resolves to the **owner's** account and counts against the owner's personal subscription.
This means:
- There is no separate organization plan, invoice, or payment method.
- All organization API usage is consumed from the owner's subscription quota.
- If the owner's subscription is inactive, every organization API key is inactive until the subscription is restored.
## Deleting an organization
Only the owner can delete an organization. Deleting an organization removes the team's access to its shared API keys. Be sure your team has migrated to other keys before deleting.
## Get started
Ready to set up your team? Head to your [dashboard](https://carsxe.com/dashboard) to create an organization, invite members, and generate your first organization API key.
---
## CarsXE for Parking Applications
URL: https://docs.carsxe.com/docs/guides/parking
How parking and valet applications use CarsXE to match vehicles to suitable spaces — dimensions, weight, EV detection, vehicle classification, and a complete search flow.
Task: Filter and rank parking locations using CarsXE vehicle dimensions, weight, fuel type, and body classification.
Prerequisites:
- A valid CarsXE API key with access to Plate Decoder and Specifications.
- A plate (plus state/country) or VIN for the arriving vehicle.
- Local parking-spot constraints (max length, width, height) to compare against the returned attributes.
Outcome: A plate or VIN lookup returns dimensions and fuel type that a parking filter can use to exclude unfit spaces and prioritize EV charging.
Verification:
- A Plate Decoder request returns a VIN; the follow-up Specifications request includes `overall_length`, `overall_width`, and `overall_height`.
- The parking filter keeps only spots whose `maxLength`/`maxWidth`/`maxHeight` are greater than or equal to those parsed dimensions.
- When `attributes.fuel_type` is `Electric` or `Plug-in Hybrid`, the UI ranks charging-enabled spots first.
Related: /docs/guides/parking, /docs/products/plate-decoder, /docs/products/specifications
Parking applications face a unique challenge: matching vehicles with suitable parking spaces. Whether it's ensuring a large truck can fit in a garage, directing EV owners to charging-enabled spots, or filtering results based on vehicle height restrictions, having accurate vehicle data is essential.
CarsXE provides two APIs that parking companies can compose to deliver intelligent, personalized parking experiences:
1. **[Plate Decoder](/docs/products/plate-decoder)** — get vehicle information from a license plate
2. **[Specifications](/docs/products/specifications)** — get detailed specifications from a VIN
## Common use cases
### 1. Size-based parking recommendations
**Challenge:** A truck owner in NYC needs to find parking spots that can accommodate their vehicle's dimensions.
**Solution:** Use CarsXE to automatically determine vehicle dimensions and filter parking options accordingly.
```js
// User enters license plate: "ABC1234"
const plateData = await carsxe.platedecoder({
plate: "ABC1234",
state: "NY",
country: "US",
});
// Get detailed specs from VIN
const specs = await carsxe.specs({
vin: plateData.vin,
});
// Extract dimensions
const dimensions = {
length: specs.attributes.overall_length, // e.g., "231.80 in."
width: specs.attributes.overall_width, // e.g., "80.00 in."
height: specs.attributes.overall_height, // e.g., "76.60 in."
};
// Filter parking spots
const suitableSpots = parkingLocations.filter((spot) => {
return (
spot.maxLength >= parseDimension(dimensions.length) &&
spot.maxWidth >= parseDimension(dimensions.width) &&
spot.maxHeight >= parseDimension(dimensions.height)
);
});
```
**Key vehicle attributes:**
- `overall_length` — total vehicle length
- `overall_width` — total vehicle width
- `overall_height` — total vehicle height
- `wheelbase_length` — distance between front and rear axles
- `turning_diameter` — turning radius for tight spaces
### 2. EV charging station prioritization
**Challenge:** Show EV charging availability prominently to electric vehicle owners.
**Solution:** Detect if a vehicle is electric and highlight charging-enabled parking locations.
```js
// Decode license plate
const plateData = await carsxe.platedecoder({
plate: "TESLA99",
state: "CA",
country: "US",
});
// Get detailed specs
const specs = await carsxe.specs({
vin: plateData.vin,
});
// Check if vehicle is electric
const isEV =
specs.attributes.fuel_type === "Electric" ||
specs.attributes.fuel_type === "Plug-in Hybrid";
// Customize UI for EV owners
if (isEV) {
// Show EV charging icon
// Filter/sort by charging availability
// Display charging rates and connector types
// Show estimated charging time
}
```
**Fuel types to check:**
- `Electric` — fully electric vehicles
- `Plug-in Hybrid` — PHEVs requiring charging
- `Gasoline` — traditional gas vehicles
- `Diesel` — diesel vehicles
- `Hybrid` — non-plug-in hybrids
### 3. Vehicle type classification
**Challenge:** Different parking rates and restrictions for motorcycles, compact cars, SUVs, and commercial vehicles.
**Solution:** Automatically classify vehicles and apply appropriate pricing and restrictions.
```js
const specs = await carsxe.specs({ vin: userVIN });
// Extract vehicle classification
const vehicleType = specs.attributes.type; // e.g., "Sedan/Saloon", "SUV", "Pickup"
const bodyStyle = specs.attributes.style; // e.g., "SEDAN 4-DR"
const vehicleClass = specs.attributes.vehicle_class; // "1" (Light), "2" (Medium), etc.
// Apply parking rules
let parkingRate;
let restrictions = [];
if (vehicleType.includes("Pickup") || vehicleType.includes("SUV")) {
parkingRate = rates.oversized;
restrictions.push("Not suitable for compact spaces");
} else if (vehicleType.includes("Sedan") || vehicleType.includes("Hatchback")) {
parkingRate = rates.standard;
} else if (vehicleType.includes("Motorcycle")) {
parkingRate = rates.motorcycle;
restrictions.push("Motorcycle parking only");
}
```
**Vehicle classification attributes:**
- `type` — general vehicle type (Sedan, SUV, Pickup, Motorcycle, etc.)
- `style` — body style (SEDAN 4-DR, COUPE 2-DR, etc.)
- `category` — vehicle category
- `vehicle_class` — weight class (1 = Light, 2 = Medium, 3 = Heavy)
- `size` — size classification
### 4. Weight restrictions
**Challenge:** Parking garages often have weight limits for structural safety.
**Solution:** Check vehicle weight against garage capacity.
```js
const specs = await carsxe.specs({ vin: userVIN });
// Extract weight information
const curbWeight = parseDimension(specs.attributes.curb_weight); // "4090 lbs"
const gvwr = specs.attributes.gross_vehicle_weight_rating;
const vehicleRating = specs.attributes.vehicle_rating; // "Light", "Medium", "Heavy"
// Check against garage limits
const garageMaxWeight = 6000; // lbs
if (curbWeight > garageMaxWeight) {
// Show warning or exclude location
return {
suitable: false,
reason: `Vehicle weight (${curbWeight} lbs) exceeds garage limit (${garageMaxWeight} lbs)`,
};
}
```
## Implementation guide
### Step 1: Capture vehicle information
Parking apps can capture vehicle data in several ways.
**Option A: license plate entry**
```js
// User manually enters their plate
const plateData = await carsxe.platedecoder({
plate: "7XER187",
state: "CA",
country: "US",
});
// Extract VIN for detailed specs
const vin = plateData.vin;
```
**Option B: VIN entry**
```js
// User enters VIN directly (e.g., from registration)
const specs = await carsxe.specs({
vin: "WBAFR7C57CC811956",
});
```
**Option C: user profile**
```js
// Store vehicle info in user profile on signup
// Retrieve for all future parking searches
const userVehicle = getUserProfile().vehicle;
```
### Step 2: Extract key data points
Based on your parking application's needs, extract the relevant attributes:
```js
const parkingRelevantData = {
// Dimensions
length: specs.attributes.overall_length,
width: specs.attributes.overall_width,
height: specs.attributes.overall_height,
// Weight
weight: specs.attributes.curb_weight,
// Type
vehicleType: specs.attributes.type,
bodyStyle: specs.attributes.style,
// Fuel
fuelType: specs.attributes.fuel_type,
isEV: specs.attributes.fuel_type === "Electric",
// Capacity
seating: specs.attributes.standard_seating,
// Identity
make: specs.attributes.make,
model: specs.attributes.model,
year: specs.attributes.year,
// Additional
turningDiameter: specs.attributes.turning_diameter,
};
```
### Step 3: Filter and personalize results
Use the extracted data to customize the parking experience:
```js
function filterParkingLocations(spots, vehicleData) {
return spots
.filter((spot) => {
// Check dimensions
if (spot.maxHeight && parseDimension(vehicleData.height) > spot.maxHeight) {
return false;
}
if (spot.maxLength && parseDimension(vehicleData.length) > spot.maxLength) {
return false;
}
// Check weight
if (spot.maxWeight && parseDimension(vehicleData.weight) > spot.maxWeight) {
return false;
}
return true;
})
.map((spot) => {
// Add relevance score
spot.relevanceScore = 0;
// Boost EV charging spots for EV owners
if (vehicleData.isEV && spot.hasEVCharging) {
spot.relevanceScore += 10;
spot.badges = spot.badges || [];
spot.badges.push("EV Charging Available");
}
// Boost oversized spots for large vehicles
if (parseDimension(vehicleData.length) > 200 && spot.oversized) {
spot.relevanceScore += 5;
}
return spot;
})
.sort((a, b) => b.relevanceScore - a.relevanceScore);
}
```
## API quick reference
### Plate Decoder
**Endpoint:** `GET https://api.carsxe.com/platedecoder`
**Required parameters:**
- `key` — your CarsXE API key
- `plate` — license plate number
- `state` — two-letter state code (for US, CA, AU)
- `country` — two-letter country code (optional for US)
```bash
curl -G https://api.carsxe.com/platedecoder \
-d key=YOUR_API_KEY \
-d plate=7XER187 \
-d state=CA
```
**Key response fields:**
- `vin` — Vehicle Identification Number (use for detailed specs)
- `make` — vehicle manufacturer
- `model` — vehicle model
- `year` / `registration_year` — model/registration year
- `description` — full vehicle description
### Specifications
**Endpoint:** `GET https://api.carsxe.com/specs`
**Required parameters:**
- `key` — your CarsXE API key
- `vin` — 17-character Vehicle Identification Number
**Optional parameters:**
- `format` — response format (`json` or `xml`)
- `deepdata` — set to `1` for additional data (slower response)
```bash
curl -G https://api.carsxe.com/specs \
-d key=YOUR_API_KEY \
-d vin=WBAFR7C57CC811956
```
**Key response fields for parking apps:**
| Attribute | Description | Example |
|---|---|---|
| `overall_length` | Total vehicle length | `"193.10 in."` |
| `overall_width` | Total vehicle width | `"73.20 in."` |
| `overall_height` | Total vehicle height | `"57.60 in."` |
| `curb_weight` | Vehicle weight without cargo | `"4090 lbs"` |
| `fuel_type` | Type of fuel/power | `"Electric"`, `"Gasoline"` |
| `type` | Vehicle type | `"Sedan/Saloon"`, `"SUV"` |
| `style` | Body style | `"SEDAN 4-DR"` |
| `turning_diameter` | Turning circle | `"37.50 in."` |
| `wheelbase_length` | Wheelbase length | `"116.90 in."` |
## Best practices
### 1. Cache vehicle data
Store vehicle information in user profiles to avoid repeated API calls:
```js
// On first lookup
const specs = await carsxe.specs({ vin: userVIN });
// Save to user profile
await saveUserVehicle(userId, {
vin: userVIN,
specs: specs.attributes,
lastUpdated: new Date(),
cachedUntil: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), // 90 days
});
// On subsequent searches
const cachedVehicle = await getUserVehicle(userId);
if (cachedVehicle && cachedVehicle.cachedUntil > new Date()) {
// Use cached data
return cachedVehicle.specs;
} else {
// Refresh from API
return await carsxe.specs({ vin: userVIN });
}
```
### 2. Handle missing data gracefully
Not all vehicles will have complete specification data:
```js
function parseDimension(value) {
if (!value || value === "") return null;
// Parse "193.10 in." to 193.10
const parsed = parseFloat(value);
return isNaN(parsed) ? null : parsed;
}
function checkDimensions(specs, spot) {
const height = parseDimension(specs.attributes.overall_height);
// If we don't have height data, show the spot with a warning
if (!height && spot.maxHeight) {
return {
suitable: "unknown",
warning: "Unable to verify vehicle height. Please check clearance manually.",
};
}
if (height && spot.maxHeight && height > spot.maxHeight) {
return { suitable: false };
}
return { suitable: true };
}
```
### 3. Provide visual indicators
Help users understand why certain spots are recommended:
```js
function addParkingBadges(spot, vehicleData) {
const badges = [];
if (vehicleData.isEV && spot.hasEVCharging) {
badges.push({
icon: "⚡",
text: "EV Charging",
type: "success",
});
}
if (vehicleData.length > 200 && spot.oversized) {
badges.push({
icon: "🚛",
text: "Oversized Friendly",
type: "info",
});
}
if (spot.maxHeight > parseDimension(vehicleData.height) + 12) {
badges.push({
icon: "📏",
text: "Plenty of Clearance",
type: "success",
});
}
return badges;
}
```
### 4. Error handling
```js
async function getVehicleSpecs(plateOrVIN, isPlate = true) {
try {
if (isPlate) {
const plateData = await carsxe.platedecoder({
plate: plateOrVIN.plate,
state: plateOrVIN.state,
country: plateOrVIN.country,
});
if (!plateData.success) {
throw new Error("Unable to decode license plate");
}
if (!plateData.vin) {
return {
success: false,
error: "VIN not available for this plate",
basicInfo: plateData, // Still return basic info
};
}
const specs = await carsxe.specs({ vin: plateData.vin });
return { success: true, data: specs };
} else {
const specs = await carsxe.specs({ vin: plateOrVIN });
return { success: true, data: specs };
}
} catch (error) {
console.error("Vehicle lookup error:", error);
return {
success: false,
error: error.message,
// Fallback: proceed with manual vehicle entry
requiresManualEntry: true,
};
}
}
```
See the [error reference](/docs/guides/errors) for the complete status-code catalog.
## International support
The Plate Decoder API supports license plates from 50+ countries across 6 continents. This enables global parking applications to serve diverse markets:
- **North America:** US, Canada, Mexico, Costa Rica
- **Europe:** UK, Germany, France, Spain, Italy, Netherlands, and 25+ more
- **Asia:** India, China, Singapore, Malaysia, UAE, and more
- **Oceania:** Australia, New Zealand
- **South America:** Brazil, Argentina, Chile, Colombia, and more
- **Africa:** South Africa, Nigeria, Tunisia
See [Supported Countries](/docs/guides/supported-countries) for the full country list and per-endpoint coverage. If your traffic originates in Europe, route requests through the EU deployment — see [Latency & Regions](/docs/guides/latency-and-regions).
## Pricing and sandbox
**Free sandbox:** The Specifications API is included in the free Sandbox as part of the shared lifetime quota (up to 100 API calls), allowing you to test the integration before committing.
**Plate Decoder:** Included in the free Sandbox as part of the shared lifetime quota (up to 100 API calls). See the [pricing page](https://carsxe.com/pricing) for details.
**Production use:** Contact sales for volume pricing and enterprise plans tailored to parking applications.
## Next steps
1. [Sign in and get a free API key](https://carsxe.com/signin)
2. Review the [Plate Decoder](/docs/products/plate-decoder) documentation
3. Review the [Specifications](/docs/products/specifications) documentation
4. Test the integration in your development environment
5. Contact [support@carsxe.com](mailto:support@carsxe.com) for integration assistance
## Example: complete parking search flow
A complete example showing how a parking app might implement vehicle-aware search:
```js
import { CarsXE } from "carsxe-api";
const carsxe = new CarsXE("YOUR_API_KEY");
async function searchParking(userInput, parkingLocations) {
// Step 1: Get vehicle data
let vehicleData;
if (userInput.plate) {
const plateData = await carsxe.platedecoder({
plate: userInput.plate,
state: userInput.state,
country: userInput.country || "US",
});
if (plateData.vin) {
const specs = await carsxe.specs({ vin: plateData.vin });
vehicleData = extractParkingData(specs.attributes);
}
} else if (userInput.vin) {
const specs = await carsxe.specs({ vin: userInput.vin });
vehicleData = extractParkingData(specs.attributes);
}
// Step 2: Filter locations
const filteredSpots = parkingLocations.filter((spot) => {
return isVehicleSuitable(vehicleData, spot);
});
// Step 3: Rank by relevance
const rankedSpots = filteredSpots
.map((spot) => ({
...spot,
relevance: calculateRelevance(vehicleData, spot),
badges: generateBadges(vehicleData, spot),
}))
.sort((a, b) => b.relevance - a.relevance);
return {
vehicleData,
results: rankedSpots,
filteredCount: parkingLocations.length - filteredSpots.length,
};
}
function extractParkingData(attributes) {
return {
length: parseFloat(attributes.overall_length) || null,
width: parseFloat(attributes.overall_width) || null,
height: parseFloat(attributes.overall_height) || null,
weight: parseFloat(attributes.curb_weight) || null,
isEV: attributes.fuel_type === "Electric",
isPHEV: attributes.fuel_type === "Plug-in Hybrid",
type: attributes.type,
make: attributes.make,
model: attributes.model,
year: attributes.year,
};
}
function isVehicleSuitable(vehicle, spot) {
if (!vehicle) return true; // No vehicle data, show all
if (spot.maxHeight && vehicle.height && vehicle.height > spot.maxHeight) {
return false;
}
if (spot.maxLength && vehicle.length && vehicle.length > spot.maxLength) {
return false;
}
if (spot.maxWeight && vehicle.weight && vehicle.weight > spot.maxWeight) {
return false;
}
return true;
}
function calculateRelevance(vehicle, spot) {
let score = 0;
// EV charging match
if ((vehicle.isEV || vehicle.isPHEV) && spot.hasEVCharging) {
score += 20;
}
// Comfortable fit (not too tight)
if (vehicle.height && spot.maxHeight) {
const clearance = spot.maxHeight - vehicle.height;
if (clearance > 12) score += 10; // 1 foot+ clearance
}
// Covered parking bonus for all
if (spot.covered) score += 5;
// Security features
if (spot.security24_7) score += 5;
return score;
}
function generateBadges(vehicle, spot) {
const badges = [];
if ((vehicle.isEV || vehicle.isPHEV) && spot.hasEVCharging) {
badges.push({ text: "EV Charging", icon: "⚡", variant: "success" });
}
if (vehicle.length > 200 && spot.oversized) {
badges.push({ text: "Large Vehicle OK", icon: "🚛", variant: "info" });
}
return badges;
}
// Usage
const results = await searchParking(
{
plate: "7XER187",
state: "CA",
},
allParkingLocations,
);
```
## Support
Have questions about integrating CarsXE into your parking application?
- **Email:** [support@carsxe.com](mailto:support@carsxe.com)
- **API status:** [status.carsxe.com](https://status.carsxe.com)
---
## Rate Limits & Quotas
URL: https://docs.carsxe.com/docs/guides/rate-limits
How CarsXE usage limits work — included monthly volume, the 429 response shape, overage billing, credit-wallet 402/503 responses, usage alerts, and how to handle limits in code.
Task: Stay within CarsXE rate limits and plan request throughput safely.
Prerequisites:
- A CarsXE API key and access to the developer dashboard usage view.
- The endpoint name, request unit count, and whether the account uses quotas or a credit wallet.
Outcome: Requests stop retrying permanent quota or credit failures, retry transient billing failures with bounded backoff, and reuse one `Idempotency-Key` for the same logical credit-wallet request.
Verification:
- A quota-limited request with overage disabled returns `429` with numeric `usage.current`, `usage.limit`, and `usage.remaining`; the client does not retry when `usage.remaining` is `0`.
- An underfunded credit-wallet request returns `402` and leaves `credits.remaining` unchanged.
- A transient credit-wallet billing failure returns `503`; retries reuse the same `Idempotency-Key`, and the wallet records at most one deduction for the logical request.
Related: /docs/guides/rate-limits, /docs/guides/errors, /docs/get-started
CarsXE limits are **volume-based quotas** tied to your subscription, not per-second throttles. Each API has an included monthly volume for your tier; when you reach it, what happens next depends on your overage settings. This page explains how the quotas work, exactly what a `429` looks like, and how to handle limits gracefully in code.
There are no per-second request throttles on standard plans, but keep burst concurrency reasonable — extremely
aggressive parallel traffic can still be rejected upstream before it reaches your quota.
---
## How quotas work
- **Per-API quotas.** Each API (Specs, Market Value, History, …) has its own included monthly volume, determined by your subscription tier. A few related APIs share a combined quota.
- **Monthly reset.** Usage counters reset at the start of each billing period. Sandbox lifetime allowances are one-time — they do not reset monthly.
- **Units, not requests.** Most requests consume one billable unit. Bulk endpoints consume multiple units in one request — for example [Recalls Batch](/api-reference/recalls/submit-a-bulk-recalls-batch) (one per VIN) and [YMM Options](/docs/products/ymm-options) bulk variants (`dimension=variants` + year + make → one per model; see `modelCount`). Some APIs bill per returned result instead of per request — see [How Billing Units Work](/docs/guides/billing-units).
- **Failed validation is free.** Requests rejected with a `400` validation error (missing VIN, bad parameter, etc.) are blocked before any lookup and don't count against your quota.
- **Plan-gated APIs.** Some APIs aren't included in lower tiers at all. Calling one returns a `403` — see [Errors](/docs/guides/errors) — not a `429`.
You can see your current usage per API at any time on the [developer dashboard](https://carsxe.com/dashboard/developer).
---
## What happens when you hit the limit
There are two possible behaviors, controlled by your **overage billing preference** in the dashboard:
| Overage billing | Behavior past the included quota |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **Enabled** (default on plans with overage pricing) | Requests keep succeeding. Each unit past your included volume is billed at your tier's overage rate. You will never see a quota `429`. |
| **Disabled** (opt-out) | Requests are rejected with a `429` until the period resets or you re-enable overage. |
Enterprise plans use custom pricing and monthly invoicing — included volume and overage terms are set in your contract.
---
## The 429 response
Quota errors use the standard [error envelope](/docs/guides/errors) plus a `usage` object:
Units consumed so far this billing period (or in total, for Sandbox lifetime allowances).
Your included volume for this API on your current tier.
Units left before the limit. 0 when the request was rejected.
The `message` tells you which API hit its limit, the billing period (month/year), your tier, and the exact numbers. Variants you may see:
- `This request requires N units.` — appended when a bulk request would exceed the limit even though `current < limit`. Reduce the batch size to fit within `remaining`, or split it across billing periods.
- `Please upgrade your tier to continue using the API.` — appended for one-time (Sandbox) allowances that never reset. Waiting won't help; upgrade to continue.
- `Enable overage billing in your dashboard billing preferences to continue with overage charges: …` — appended when you've opted out of overage but your plan supports it. Re-enable overage on the [developer dashboard](https://carsxe.com/dashboard/developer) and the same request will succeed immediately.
---
## Credit-wallet accounts
Accounts billed from a **credit wallet** don't have per-API monthly quotas, so they never see a quota `429`. Each call deducts credits from the wallet instead, and the two failure modes below replace it.
| Status | When | Retry? |
| ------ | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| `402` | The wallet doesn't hold enough credits for this request. | No — add credits or enable auto-recharge first. |
| `503` | Billing couldn't be verified: an auto-recharge is still settling, or a transient backend problem. | Yes — retry with backoff, reusing the same `Idempotency-Key`. |
### 402 Payment Required
Credits in the wallet when the request was checked.
Credits this request would have consumed (per-call cost × units).
Credits left after the attempt. Unchanged from available, because a denied request deducts nothing.
A `402` can also be returned **after** the upstream lookup succeeded, if the wallet ran out between the pre-check and the deduction. Nothing is charged and no data is returned in that case, so treat it the same way.
### 503 Service Unavailable
Unlike a quota `429`, a `503` **is** transient — retry it with exponential backoff. The most common cause is an auto-recharge that hasn't settled yet; it usually clears within a few seconds.
### Idempotency
Send an `Idempotency-Key` header on any request you might retry. CarsXE deduplicates wallet deductions only when the same key is reused for the same logical request (same endpoint, parameters, and unit count), within 24 hours of the first accepted attempt. Requests **without** the header are billed independently, so a retry deducts a second time. This matters most on bulk submits, where one retry can cost many credits.
---
## Usage alerts
You don't have to discover a quota `429` in production. CarsXE emails the account owner when an API reaches **80%**, **90%**, and **100%** of its included volume, so you can upgrade or enable overage before requests start failing.
---
> Truncated for agent context budget. Use /llms.txt and per-page `.md` URLs for the full corpus.