Examples
Practical code examples and integration patterns for Auto.dev APIs
Examples & Integration Patterns
Explore real-world examples and integration patterns for Auto.dev APIs. These examples demonstrate best practices, error handling, and how to combine multiple APIs for powerful automotive applications.
TypeScript SDK Examples
Basic VIN Decode with Type Safety
Here's a complete TypeScript example showing proper error handling and type safety:
// Auto.dev VIN Decode SDK Example
interface ApiError {
code: string
message: string
details?: string
}
interface VinDecodeSuccess {
success: true
data: {
vin: string
year: number
make: string
model: string
trim: string
engine: string
transmission: string
drivetrain: string
fuelType: string
doors: number
seats: number
confidence: number
}
}
interface VinDecodeError {
success: false
error: ApiError
}
type VinDecodeResponse = VinDecodeSuccess | VinDecodeError
class AutoDevClient {
constructor(private apiKey: string) {}
async decodeVin(vin: string): Promise<VinDecodeResponse> {
const response = await fetch(`https://api.auto.dev/vin/decode/${vin}`, {
headers: {
Authorization: `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
})
return response.json()
}
}
// Usage with proper type checking
const client = new AutoDevClient('YOUR_API_KEY')
const result = await client.decodeVin('1HGBH41JXMN109186')
if (result.success) {
// TypeScript knows this is VinDecodeSuccess
console.log(`Vehicle: ${result.data.year} ${result.data.make} ${result.data.model}`)
// Type-safe property access
const engine = result.data.engine
// Confidence score validation
if (result.data.confidence > 0.95) {
console.log('High confidence decode')
}
} else {
// TypeScript knows this is VinDecodeError
console.error(`Error ${result.error.code}: ${result.error.message}`)
}
Complete Vehicle Profile Builder
Combine multiple APIs to build a comprehensive vehicle profile:
interface VehicleProfile {
basic: VinDecodeResponse
specifications?: SpecificationsResponse
listings?: VehicleListingsResponse
photos?: VehiclePhotosResponse
recalls?: VehicleRecallsResponse
}
class VehicleProfileBuilder {
constructor(private client: AutoDevClient) {}
async buildProfile(vin: string): Promise<VehicleProfile> {
const profile: VehicleProfile = {
basic: await this.client.decodeVin(vin),
}
// Only fetch additional data if VIN decode was successful
if (profile.basic.success) {
const { year, make, model } = profile.basic.data
// Fetch specifications (Growth/Scale plans)
try {
profile.specifications = await this.client.getSpecifications({ year, make, model })
} catch (error) {
console.warn('Specifications not available:', error)
}
// Fetch current listings
try {
profile.listings = await this.client.getListings({ year, make, model })
} catch (error) {
console.warn('Listings not available:', error)
}
// Fetch vehicle photos
try {
profile.photos = await this.client.getPhotos(vin)
} catch (error) {
console.warn('Photos not available:', error)
}
// Check for recalls (Growth/Scale plans)
try {
profile.recalls = await this.client.getRecalls({ year, make, model })
} catch (error) {
console.warn('Recalls not available:', error)
}
}
return profile
}
}
// Usage
const builder = new VehicleProfileBuilder(client)
const profile = await builder.buildProfile('1HGBH41JXMN109186')
if (profile.basic.success) {
console.log('Vehicle Profile:', {
vehicle: `${profile.basic.data.year} ${profile.basic.data.make} ${profile.basic.data.model}`,
hasSpecs: !!profile.specifications?.success,
listingCount: profile.listings?.success ? profile.listings.data.length : 0,
photoCount: profile.photos?.success ? profile.photos.data.retail.length : 0,
recallCount: profile.recalls?.success ? profile.recalls.data.length : 0,
})
}
Real-World Use Cases
Dealership Inventory Management
Automatically populate vehicle details when adding inventory:
class DealershipInventory {
constructor(private autodev: AutoDevClient, private inventory: InventoryDB) {}
async addVehicle(vin: string, askingPrice: number): Promise<void> {
// Decode VIN for basic info
const vinData = await this.autodev.decodeVin(vin)
if (!vinData.success) {
throw new Error(`Invalid VIN: ${vinData.error.message}`)
}
// Get current market listings for pricing intelligence
const listings = await this.autodev.getListings({
year: vinData.data.year,
make: vinData.data.make,
model: vinData.data.model,
trim: vinData.data.trim,
})
let marketAnalysis = null
if (listings.success) {
const prices = listings.data.map((l) => l.retailListing.price)
marketAnalysis = {
averagePrice: prices.reduce((a, b) => a + b, 0) / prices.length,
minPrice: Math.min(...prices),
maxPrice: Math.max(...prices),
totalListings: prices.length,
}
}
// Get specifications for detailed description
const specs = await this.autodev.getSpecifications({
year: vinData.data.year,
make: vinData.data.make,
model: vinData.data.model,
})
// Save to inventory with enriched data
await this.inventory.save({
vin,
askingPrice,
...vinData.data,
marketAnalysis,
specifications: specs.success ? specs.data : null,
addedAt: new Date(),
status: 'available',
})
}
}
Insurance Quote Calculator
Calculate insurance premiums using vehicle data:
class InsuranceCalculator {
constructor(private autodev: AutoDevClient) {}
async calculatePremium(vin: string, driverAge: number, location: string): Promise<number> {
// Get vehicle details
const vehicle = await this.autodev.decodeVin(vin)
if (!vehicle.success) throw new Error('Invalid VIN')
// Get safety ratings
const recalls = await this.autodev.getRecalls({
year: vehicle.data.year,
make: vehicle.data.make,
model: vehicle.data.model,
})
// Base premium calculation
let premium = this.getBasePremium(vehicle.data.year, vehicle.data.make)
// Safety adjustments
if (vehicle.data.safety?.nhtsa_overall >= 4) {
premium *= 0.9 // 10% discount for high safety rating
}
// Recall penalty
if (recalls.success && recalls.data.length > 0) {
premium *= 1.05 // 5% increase for active recalls
}
// Age and location adjustments
premium *= this.getAgeMultiplier(driverAge)
premium *= this.getLocationMultiplier(location)
return Math.round(premium * 100) / 100
}
private getBasePremium(year: number, make: string): number {
const age = new Date().getFullYear() - year
const makeMultipliers: Record<string, number> = {
Honda: 0.8,
Toyota: 0.8,
BMW: 1.3,
'Mercedes-Benz': 1.4,
Porsche: 1.8,
}
return (1000 - age * 50) * (makeMultipliers[make] || 1.0)
}
private getAgeMultiplier(age: number): number {
if (age < 25) return 1.5
if (age < 65) return 1.0
return 1.2
}
private getLocationMultiplier(location: string): number {
// Simplified location-based multiplier
const locationMultipliers: Record<string, number> = {
urban: 1.2,
suburban: 1.0,
rural: 0.8,
}
return locationMultipliers[location] || 1.0
}
}
Fleet Management Dashboard
Track and analyze fleet vehicles:
interface FleetVehicle {
id: string
vin: string
assignedDriver?: string
mileage: number
lastService: Date
profile?: VehicleProfile
}
class FleetManager {
constructor(private autodev: AutoDevClient) {}
async analyzeFleet(vehicles: FleetVehicle[]): Promise<FleetAnalysis> {
const analysis: FleetAnalysis = {
totalVehicles: vehicles.length,
averageAge: 0,
maintenanceAlerts: [],
recallAlerts: [],
costAnalysis: null,
}
// Enrich each vehicle with Auto.dev data
for (const vehicle of vehicles) {
vehicle.profile = await this.buildVehicleProfile(vehicle.vin)
if (vehicle.profile.basic.success) {
const age = new Date().getFullYear() - vehicle.profile.basic.data.year
analysis.averageAge += age
// Check for recalls
if (vehicle.profile.recalls?.success && vehicle.profile.recalls.data.length > 0) {
analysis.recallAlerts.push({
vehicleId: vehicle.id,
vin: vehicle.vin,
recalls: vehicle.profile.recalls.data.length,
})
}
// Maintenance predictions based on mileage and age
if (vehicle.mileage > 75000 || age > 8) {
analysis.maintenanceAlerts.push({
vehicleId: vehicle.id,
reason: vehicle.mileage > 75000 ? 'High Mileage' : 'Vehicle Age',
priority: vehicle.mileage > 100000 ? 'High' : 'Medium',
})
}
}
}
analysis.averageAge = analysis.averageAge / vehicles.length
return analysis
}
private async buildVehicleProfile(vin: string): Promise<VehicleProfile> {
// Use the VehicleProfileBuilder from earlier example
const builder = new VehicleProfileBuilder(this.autodev)
return builder.buildProfile(vin)
}
}
interface FleetAnalysis {
totalVehicles: number
averageAge: number
maintenanceAlerts: Array<{
vehicleId: string
reason: string
priority: 'Low' | 'Medium' | 'High'
}>
recallAlerts: Array<{
vehicleId: string
vin: string
recalls: number
}>
costAnalysis: any
}
Integration Patterns
Rate Limiting and Retry Logic
Handle API rate limits gracefully:
class RateLimitedClient {
private requestQueue: Array<() => Promise<any>> = []
private isProcessing = false
private lastRequestTime = 0
private minInterval = 100 // Minimum time between requests in ms
constructor(private autodev: AutoDevClient) {}
async queueRequest<T>(requestFn: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.requestQueue.push(async () => {
try {
const result = await this.executeWithRetry(requestFn)
resolve(result)
} catch (error) {
reject(error)
}
})
if (!this.isProcessing) {
this.processQueue()
}
})
}
private async processQueue(): Promise<void> {
this.isProcessing = true
while (this.requestQueue.length > 0) {
const request = this.requestQueue.shift()!
// Ensure minimum interval between requests
const timeSinceLastRequest = Date.now() - this.lastRequestTime
if (timeSinceLastRequest < this.minInterval) {
await this.sleep(this.minInterval - timeSinceLastRequest)
}
await request()
this.lastRequestTime = Date.now()
}
this.isProcessing = false
}
private async executeWithRetry<T>(requestFn: () => Promise<T>, maxRetries = 3, baseDelay = 1000): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await requestFn()
} catch (error: any) {
if (attempt === maxRetries) throw error
// Exponential backoff for rate limit errors
if (error.status === 429) {
const delay = baseDelay * Math.pow(2, attempt)
await this.sleep(delay)
continue
}
throw error
}
}
throw new Error('Max retries exceeded')
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms))
}
}
Caching Strategy
Implement intelligent caching for frequently accessed data:
interface CacheEntry<T> {
data: T
timestamp: number
ttl: number
}
class CachedAutoDevClient {
private cache = new Map<string, CacheEntry<any>>()
private readonly DEFAULT_TTL = 1000 * 60 * 60 // 1 hour
constructor(private autodev: AutoDevClient) {}
async decodeVin(vin: string): Promise<VinDecodeResponse> {
const cacheKey = `vin:${vin}`
const cached = this.getFromCache<VinDecodeResponse>(cacheKey)
if (cached) {
return cached
}
const result = await this.autodev.decodeVin(vin)
// Only cache successful responses
if (result.success) {
this.setCache(cacheKey, result, this.DEFAULT_TTL)
}
return result
}
async getSpecifications(params: { year: number; make: string; model: string }): Promise<any> {
const cacheKey = `specs:${params.year}:${params.make}:${params.model}`
const cached = this.getFromCache(cacheKey)
if (cached) {
return cached
}
const result = await this.autodev.getSpecifications(params)
if (result.success) {
// Specs change less frequently, longer TTL
this.setCache(cacheKey, result, this.DEFAULT_TTL * 24) // 24 hours
}
return result
}
private getFromCache<T>(key: string): T | null {
const entry = this.cache.get(key)
if (!entry) return null
if (Date.now() - entry.timestamp > entry.ttl) {
this.cache.delete(key)
return null
}
return entry.data
}
private setCache<T>(key: string, data: T, ttl: number): void {
this.cache.set(key, {
data,
timestamp: Date.now(),
ttl,
})
}
clearCache(): void {
this.cache.clear()
}
}
Error Handling Best Practices
Comprehensive Error Handler
enum AutoDevErrorCode {
INVALID_VIN = 'INVALID_VIN',
VIN_NOT_FOUND = 'VIN_NOT_FOUND',
RATE_LIMIT = 'RATE_LIMIT',
UNAUTHORIZED = 'UNAUTHORIZED',
PLAN_LIMIT = 'PLAN_LIMIT',
NETWORK_ERROR = 'NETWORK_ERROR',
}
class AutoDevError extends Error {
constructor(public code: AutoDevErrorCode, message: string, public statusCode?: number, public retryable = false) {
super(message)
this.name = 'AutoDevError'
}
}
class ErrorHandler {
static handleApiError(error: any): AutoDevError {
if (error.status === 401) {
return new AutoDevError(AutoDevErrorCode.UNAUTHORIZED, 'Invalid API key or authentication failed', 401)
}
if (error.status === 429) {
return new AutoDevError(
AutoDevErrorCode.RATE_LIMIT,
'Rate limit exceeded',
429,
true, // Retryable
)
}
if (error.status === 403) {
return new AutoDevError(AutoDevErrorCode.PLAN_LIMIT, 'API not available on current plan', 403)
}
if (!navigator.onLine) {
return new AutoDevError(AutoDevErrorCode.NETWORK_ERROR, 'Network connection unavailable', undefined, true)
}
// Generic error
return new AutoDevError(AutoDevErrorCode.NETWORK_ERROR, error.message || 'Unknown API error', error.status)
}
static async withErrorHandling<T>(operation: () => Promise<T>, fallback?: T): Promise<T | null> {
try {
return await operation()
} catch (error) {
const autoDevError = this.handleApiError(error)
console.error(`Auto.dev API Error [${autoDevError.code}]:`, autoDevError.message)
// Return fallback value if provided
if (fallback !== undefined) {
return fallback
}
// Re-throw if no fallback
throw autoDevError
}
}
}
// Usage
const safeVinDecode = await ErrorHandler.withErrorHandling(
() => client.decodeVin('INVALID_VIN'),
null, // Fallback to null on error
)
if (safeVinDecode?.success) {
console.log('VIN decoded successfully')
} else {
console.log('VIN decode failed, using fallback')
}
These examples demonstrate production-ready patterns for integrating Auto.dev APIs into real applications with proper error handling, caching, rate limiting, and type safety.