The carsxe package is the official CarsXE client for Python. It is async-first, built on httpx and pydantic v2. Requires Python 3.9 or later.
Installation
pip install carsxe
# uv add carsxe
# poetry add carsxeQuick start
The client is an async context manager. Use async with so the underlying HTTP connection is closed when you're done.
import asyncio
import os
from carsxe import CarsXE
async def main():
async with CarsXE(api_key=os.environ['CARSXE_API_KEY']) as client:
result = await client.decode_vin('WBAFR7C57CC811956')
print(result.data.make, result.data.model, result.data.year)
asyncio.run(main())If you need to reuse the client across many calls (e.g. in a long-running server), instantiate it directly and call await client.close() when done instead.
client = CarsXE(api_key=os.environ['CARSXE_API_KEY'])
try:
result = await client.decode_vin('WBAFR7C57CC811956')
finally:
await client.close()Methods
Core
| Method | Description |
|---|---|
decode_vin(vin) | Decode a 17-character VIN into full vehicle specifications |
get_market_value(vin, *, mileage, state, condition) | Retail, trade-in, and auction value estimates |
get_recalls(*, vin, make, model, year) | Open safety recalls — pass VIN or make/model/year |
decode_plate(plate, state) | VIN lookup from a license plate (50+ countries) |
get_vehicle_history(vin) | Title events, salvage, junk, and insurance records |
Bulk recall batch
| Method | Description |
|---|---|
submit_bulk_recall_batch(vins, *, csv, csv_url, webhook_url) | Submit a batch of VINs |
get_bulk_recall_batch_status(batch_id) | Poll job status |
get_bulk_recall_batch_results(batch_id) | Retrieve completed results |
get_bulk_recall_batch_download_url(batch_id) | Get a CSV download URL |
Error handling
By default the client raises CarsXEError on non-2xx responses. The exception carries status_code, code, and message.
from carsxe import CarsXE, CarsXEError
import os
async with CarsXE(api_key=os.environ['CARSXE_API_KEY']) as client:
try:
result = await client.decode_vin('WBAFR7C57CC811956')
except CarsXEError as e:
print(e.status_code, e.code, e.message)Pass throw_on_error=False to suppress exceptions and inspect result.error instead:
client = CarsXE(api_key=os.environ['CARSXE_API_KEY'], throw_on_error=False)
result = await client.decode_vin('INVALID')
if result.error:
print(result.error.message)Best practices
Always use async with or call close(). The SDK uses an httpx.AsyncClient internally — leaving it open leaks connections.
Store your key in an environment variable.
# .env
CARSXE_API_KEY=your_key_hereimport os
from dotenv import load_dotenv
load_dotenv()
api_key = os.environ['CARSXE_API_KEY']Reuse the client. In a web server (FastAPI, Django async views), create the client once at startup and close it on shutdown — don't instantiate per-request.
# FastAPI example
from contextlib import asynccontextmanager
from fastapi import FastAPI
from carsxe import CarsXE
carsxe: CarsXE
@asynccontextmanager
async def lifespan(app: FastAPI):
global carsxe
carsxe = CarsXE(api_key=os.environ['CARSXE_API_KEY'])
yield
await carsxe.close()
app = FastAPI(lifespan=lifespan)