Error Codes
Complete catalog of API error responses, status codes, and error types
This document catalogs all possible error types that clients may encounter when using the Auto.dev API Gateway.
Error Response Structure
All API errors follow a consistent JSON structure:
interface ApiError {
status: number // HTTP status code (400, 401, 404, 500, etc.)
error: string // Human-readable error description
code: string // Programmatic error identifier
path: string // API endpoint path that generated the error
requestId: string // Unique identifier for debugging and support
suggestion?: string // Helpful guidance for resolution (optional)
message?: string // Alternative error description (legacy/some endpoints)
errorType?: string // Legacy error type classification
// Miss context (/build 404s; a /build, /vin or /specs 207 partial answer carries reason + retryable top-level, with no error block)
reason?: string // Machine-readable reason for the miss (see below)
retryable?: boolean // Whether asking again later can change the answer
detectedMarket?: { country: string; region: string } // VIN_NOT_IN_COVERAGE, by market
detectedClass?: { vehicleType: string } // VIN_NOT_IN_COVERAGE, by vehicle class
// Plan-gating fields (402 responses)
currentPlan?: string // The plan the caller is on
requiredPlan?: string // The plan needed for this feature
upgradeUrl?: string // Preferred upgrade link (tier-targeted)
upgradeLink?: string // Alias of upgradeUrl (kept for backward compat)
docsUrl?: string // Link to the plans documentation
plans?: Record<string, { price: string; rateLimit: string; features: string }>
}Field Usage Across APIs:
status- HTTP status code (universal)error- Primary error message (universal)code- Error code identifier (universal)path- Request path (universal)requestId- Debug identifier (universal)suggestion- Resolution guidance (taxes API)message- Alternative / extended error descriptionerrorType- Legacy VIN validation errorsreason,retryable- Why a/buildlookup missed, and whether to retry (also top-level on the body, and on every 207)detectedMarket,detectedClass- What put the VIN outside coverage (VIN_NOT_IN_COVERAGE)currentPlan,requiredPlan,upgradeUrl,upgradeLink,docsUrl,plans- Plan-gating context (402 responses)
207 Multi-Status Is Not an Error
/build, /vin and /specs answer 207 Multi-Status when they can name the vehicle but not the whole of what the endpoint promises. The body is a partial answer, not an error: what is known, with reason and retryable top-level and no error block. A 207 is not billed and counts toward no quota. Most HTTP clients treat a 207 as ok, so branch on the status before reading the body as a 200.
| endpoint | a 207 means | the body holds | shape |
|---|---|---|---|
/build | a decoder names the car, no record builds it | vehicle, build: null, catalog (what the matched style ships with, or null) | OEM Build Data |
/vin | a decoder names less than year, make and model, and its class or market says why | vin, vinValid, vehicle (manufacturer, type, year; make and model when named), yearAmbiguous + years when more than one year fits; no decode fields | VIN Decode |
/specs | a source holds only some of the documented fields | vehicle, specs with the held fields and null for the rest, missing[] naming the null ones | Specifications |
A /build 207:
{
"vehicle": { "vin": "1FATP8R0XT5502067", "year": 2026, "make": "Ford", "model": "Mustang", "body": "Coupe" },
"build": null,
"catalog": null,
"reason": "no_build_record",
"retryable": false
}A /vin 207, a trailer from a small maker:
{
"vin": "1T9P61527VP394134",
"vinValid": true,
"vehicle": { "vin": "1T9P61527VP394134", "year": 2027, "manufacturer": "The Metal Shop", "type": "Utility Trailers" },
"yearAmbiguous": true,
"years": [2027, 1997],
"reason": "class_not_covered",
"retryable": false
}One reason vocabulary covers the three endpoints. On /build the same codes ride a 404 too: "if decoded" means a decoder named the year, make and model; otherwise the reason rides the 404. On /vin and /specs a reason appears only on a 207.
reason | endpoints | status | means | retry |
|---|---|---|---|---|
not_yet_available | /build | 207 if decoded, else 404 | model year ahead of the catalogs | yes, the catalogs catch up within the year |
no_build_record | /build | 207 if decoded, else 404 | no record builds this VIN | no |
no_vin_record | /specs | 207 | a covered vehicle no source holds a full record for; also the reason of each missing[] entry | no |
market_not_covered | /build, /vin, /specs | /build: 207 if decoded, else 404; /vin, /specs: 207 | VIN built outside North America | no |
class_not_covered | /build, /vin, /specs | /build: 207 if decoded, else 404; /vin, /specs: 207 | motorcycle, trailer, bus or heavy truck; each page lists its endpoint's exact classes | no |
invalid_vin | /build | 404 | the check digit does not compute, or the VIN is a test pattern | no |
The full shapes are on the OEM Build Data, VIN Decode and Specifications pages.
HTTP Status Codes
400 - Bad Request
Invalid Location
Code: INVALID_LOCATION
{
"status": 400,
"error": "Invalid ZIP code format. ZIP code must be 5 digits (e.g., 90210) or 5+4 format (e.g., 90210-1234)",
"code": "INVALID_LOCATION",
"path": "/taxes/invalidzip",
"requestId": "a1b2c3d4e5f6g7h8",
"suggestion": "Please provide a valid 5-digit ZIP code or ZIP+4 format"
}Invalid VIN Format
Code: INVALID_VIN_FORMAT
{
"status": 400,
"error": "VIN must be exactly 17 characters containing only letters and numbers (excluding I, O, Q)",
"code": "INVALID_VIN_FORMAT",
"path": "/vin/123Invalid",
"requestId": "a1b2c3d4e5f6g7h8"
}Invalid License Plate Format
Code: INVALID_PLATE_FORMAT
{
"status": 400,
"error": "License plate must be 2-8 alphanumeric characters",
"code": "INVALID_PLATE_FORMAT",
"path": "/plate/A?state=CA",
"requestId": "b2c3d4e5f6g7h8i9"
}Invalid State Code
Code: INVALID_STATE_CODE
{
"status": 400,
"error": "State must be a valid 2-letter US state code (e.g., CA, NY, TX)",
"code": "INVALID_STATE_CODE",
"path": "/plate/ABC123?state=XX",
"requestId": "c3d4e5f6g7h8i9j0"
}Invalid Parameter
Code: INVALID_PARAMETER
{
"status": 400,
"error": "Invalid parameter provided: make. This parameter does not exist in this endpoint.",
"code": "INVALID_PARAMETER",
"path": "/listings",
"requestId": "966e8386bb38f095"
}Invalid Request
Code: INVALID_REQUEST
{
"status": 400,
"error": "Invalid request format or missing required parameters",
"code": "INVALID_REQUEST",
"path": "/api/endpoint",
"requestId": "d4e5f6g7h8i9j0k1"
}401 - Unauthorized
Authentication Required
Code: UNAUTHORIZED
{
"status": 401,
"message": "Authentication required. Get your API key at https://auto.dev/dashboard/api-keys",
"code": "UNAUTHORIZED",
"path": "/vin/1HGCM82633A123456",
"requestId": "e5f6g7h8i9j0k1l2"
}402 - Payment Required
Returned when the caller's plan does not include the requested endpoint. The response body carries plan-gating context (currentPlan, requiredPlan, upgradeUrl, docsUrl, and a plans summary) so clients can render an actionable upgrade CTA without a second API call. Two response headers make the same context available without parsing the body:
X-Required-Plan— plan needed for this featureX-Current-Plan— plan the caller is currently on
Feature Not Available
Code: FEATURE_NOT_AVAILABLE
{
"status": 402,
"error": "Payment Required",
"code": "FEATURE_NOT_AVAILABLE",
"message": "This feature requires the Scale plan. You are currently on the Free plan.",
"currentPlan": "Free",
"requiredPlan": "Scale",
"upgradeUrl": "https://auto.dev/pricing?tier=Scale",
"upgradeLink": "https://auto.dev/pricing?tier=Scale",
"docsUrl": "https://docs.auto.dev/plans",
"plans": {
"Growth": { "price": "$299/mo", "rateLimit": "10 req/s", "features": "build, specs, price, recalls, tco, payments" },
"Scale": { "price": "$599/mo", "rateLimit": "50 req/s", "features": "All Growth + openrecalls, plate lookup, taxes" }
},
"path": "/openrecalls/1HGCM82633A123456",
"requestId": "f6g7h8i9j0k1l2m3"
}Payment Required (legacy)
Code: PAYMENT_REQUIRED
The original 402 shape is still returned by some legacy endpoints without plan context. New integrations should rely on FEATURE_NOT_AVAILABLE shape above.
{
"status": 402,
"error": "Payment Required",
"code": "PAYMENT_REQUIRED",
"path": "/advanced-endpoint",
"requestId": "f6g7h8i9j0k1l2m3",
"upgradeLink": "https://auto.dev/pricing"
}403 - Forbidden
Forbidden Access
Code: FORBIDDEN
{
"status": 403,
"error": "Forbidden",
"code": "FORBIDDEN",
"path": "/restricted-endpoint",
"requestId": "g7h8i9j0k1l2m3n4"
}404 - Not Found
VIN Not Found
Code: VIN_NOT_FOUND
{
"status": 404,
"error": "No vehicle data found for the provided VIN",
"code": "VIN_NOT_FOUND",
"path": "/vin/1FTFW3LDXRFB40317",
"requestId": "b2c3d4e5f6g7h8i9"
}On /vin, a 404 means no decoder could name the vehicle; one named only in part, with a class or market reason, answers a 207 instead. On /specs, a 404 means no decoder could name the make; a vehicle with a make, and specifications only in part, answers a 207. Neither 404 carries a reason.
On /build, a 404 means no decoder could name the car; a car a decoder names answers a 207. The error block carries reason and retryable, and the body repeats them top-level.
{
"status": 404,
"error": "No build data available for this vehicle.",
"code": "VIN_NOT_FOUND",
"path": "/build/1FMDU32X6RUE08716",
"requestId": "nu9cn44nt2ek5rbk",
"reason": "no_build_record",
"retryable": false
}Invalid VIN
Code: INVALID_VIN
Returned by /build when a well-formed VIN is not a vehicle: its check digit does not compute, or it is a test pattern. Distinct from INVALID_VIN_FORMAT (400), which is about the characters.
{
"status": 404,
"error": "This VIN is not a vehicle: its check digit does not compute, or it is a test pattern.",
"code": "INVALID_VIN",
"path": "/build/11111111111111111",
"requestId": "wk2t89y2ujo35ojs",
"reason": "invalid_vin",
"retryable": false
}VIN Not in Coverage
Code: VIN_NOT_IN_COVERAGE
Returned by /build when the VIN is outside build coverage and no decoder could name the car: a non-North-American market (detectedMarket), or a motorcycle, trailer or heavy truck (detectedClass). When a decoder names the car, the same VIN answers a 207 with catalog: null. Retrying will not change the outcome.
{
"status": 404,
"error": "This VIN appears to be a non-US vehicle. auto.dev currently has full coverage for US-market vehicles only.",
"code": "VIN_NOT_IN_COVERAGE",
"path": "/build/6FPFXXMX2FRD07902",
"requestId": "4k12o1tsrzyb4rai",
"detectedMarket": { "country": "AU", "region": "Oceania" },
"reason": "market_not_covered",
"retryable": false
}License Plate Not Found
Code: PLATE_NOT_FOUND
{
"status": 404,
"error": "No vehicle found for the provided license plate",
"code": "PLATE_NOT_FOUND",
"path": "/plate/NOTFOUND?state=CA",
"requestId": "h8i9j0k1l2m3n4o5"
}No Data Found
Code: NO_DATA_FOUND
{
"status": 404,
"error": "License plate found but no vehicle data available",
"code": "NO_DATA_FOUND",
"path": "/plate/ABC123?state=CA",
"requestId": "i9j0k1l2m3n4o5p6"
}Resource Not Found
Code: RESOURCE_NOT_FOUND
{
"status": 404,
"error": "Resource \"1FTFW3LDXRFB40317\" not found",
"code": "RESOURCE_NOT_FOUND",
"path": "/listings/1FTFW3LDXRFB40317",
"requestId": "966716ac29ed8147"
}422 - Unprocessable Entity
VIN Decode Failed
Code: VIN_DECODE_FAILED
{
"status": 422,
"error": "Unable to decode VIN: 1HGBH41JXMN109186",
"code": "VIN_DECODE_FAILED",
"path": "/vin/1HGBH41JXMN109186",
"requestId": "j0k1l2m3n4o5p6q7"
}Payment Calculation Error
Code: PAYMENT_CALCULATION_ERROR
{
"status": 422,
"error": "Cannot calculate payments with provided data",
"code": "PAYMENT_CALCULATION_ERROR",
"path": "/payments/1GYKPDRSXSZ102995",
"requestId": "k1l2m3n4o5p6q7r8"
}VIN Not Covered
Code: VIN_NOT_COVERED
Returned by /openrecalls when the VIN decodes successfully but falls outside the coverage of our recall data (typically grey-market imports, motorcycles, or non-standard formats). Distinct from a transient upstream failure — retrying will not change the outcome.
{
"status": 422,
"error": "VIN is not in our recall coverage. Only vehicles registered in the United States, Canada, or Mexico are supported at this time.",
"code": "VIN_NOT_COVERED",
"path": "/openrecalls/SC6GM1CAMX1234567",
"requestId": "a7b8c9d0e1f2g3h4"
}429 - Too Many Requests
Rate-limited responses carry the standard RFC 6585 + draft-ietf rate-limit headers so clients can back off deterministically:
Retry-After— seconds until the caller may retryX-RateLimit-Limit— request budget for the windowX-RateLimit-Remaining— always0on a 429X-RateLimit-Reset— Unix timestamp (seconds) when the window resets
Callers on Free that are approaching the monthly usage quota also see X-Usage-Remaining, X-Usage-Used, and X-Usage-Limit on all responses (not just 429s).
The body carries the same plan-gating context as 402 responses — upgradeLink + plans — so clients can present an upgrade CTA directly.
Rate Limit Exceeded
Code: RATE_LIMIT_EXCEEDED
{
"status": 429,
"error": "Rate limit exceeded for your Free plan. Upgrade to Growth ($299/mo, 10 req/s) at https://auto.dev/pricing for higher limits.",
"code": "RATE_LIMIT_EXCEEDED",
"path": "/vin/1HGCM82633A123456",
"requestId": "l2m3n4o5p6q7r8s9",
"upgradeLink": "https://auto.dev/pricing",
"plans": {
"Growth": { "price": "$299/mo", "rateLimit": "10 req/s", "features": "build, specs, price, recalls, tco, payments" },
"Scale": { "price": "$599/mo", "rateLimit": "50 req/s", "features": "All Growth + openrecalls, plate lookup, taxes" }
}
}500 - Internal Server Error
Internal Server Error
Code: INTERNAL_SERVER_ERROR
{
"status": 500,
"error": "500 - Internal Server Error",
"code": "INTERNAL_SERVER_ERROR",
"path": "/api/endpoint",
"requestId": "m3n4o5p6q7r8s9t0",
"message": "An unexpected error occurred, please try again later."
}503 - Service Unavailable
Source Error
Code: SOURCE_ERROR
{
"status": 503,
"error": "External service temporarily unavailable",
"code": "SOURCE_ERROR",
"path": "/payments/1GYKPDRSXSZ102995",
"requestId": "c3d4e5f6g7h8i9j0"
}Legacy Error Formats
VIN Validation (Legacy Format)
Some endpoints may still return legacy error formats:
{
"status": 400,
"error": "VIN validation failed",
"code": "VIN_VALIDATION_ERROR",
"path": "/legacy/vin/invalid",
"requestId": "n4o5p6q7r8s9t0u1",
"errorType": "VALIDATION_ERROR"
}Error Handling Best Practices
Client Implementation
- Always check the status code first
- Treat a 207 as a partial answer, not a success: on
/buildbuildisnull, on/vinthe decode fields are absent, on/specsthe fields inmissingarenull; readreason - Use the
codefield for programmatic error handling - Display the
errormessage to users (human-readable) - Log the
requestIdfor debugging and support - Implement retry logic for 5xx errors with exponential backoff, and for a miss only when
retryableistrue
Getting Help
When contacting support, please include:
- Request ID from the error response
- Full error response JSON
- Request details (endpoint, parameters, headers)
- Expected behavior vs. actual behavior