"""VIN Decoder using NHTSA vPIC API (free, no key needed).""" import re import requests def decode_vin(vin): """Decode a VIN number using NHTSA API. Returns: {make, model, year, engine, body_type, plant_country, fuel_type, error} """ vin = (vin or "").strip().upper() # Validate: 17 alphanumeric chars, no I/O/Q if not re.match(r'^[A-HJ-NPR-Z0-9]{17}$', vin): return {"error": "VIN debe tener exactamente 17 caracteres alfanumericos (sin I, O, Q)."} url = f"https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVinValues/{vin}?format=json" resp = requests.get(url, timeout=10) resp.raise_for_status() data = resp.json()["Results"][0] error_text = data.get("ErrorText", "") or "" # NHTSA returns error codes like "0 - ..." for no error has_real_error = error_text and not error_text.startswith("0") displacement = data.get("DisplacementL", "") or "" cylinders = data.get("EngineCylinders", "") or "" engine_parts = [] if displacement: engine_parts.append(f"{displacement}L") if cylinders: engine_parts.append(f"{cylinders}cyl") engine_str = " ".join(engine_parts) model_year = data.get("ModelYear", "") year_int = None if model_year: try: year_int = int(model_year) except (ValueError, TypeError): pass return { "vin": vin, "make": data.get("Make", "") or "", "model": data.get("Model", "") or "", "year": year_int, "engine": engine_str, "body_type": data.get("BodyClass", "") or "", "plant_country": data.get("PlantCountry", "") or "", "fuel_type": data.get("FuelTypePrimary", "") or "", "drive_type": data.get("DriveType", "") or "", "trim": data.get("Trim", "") or "", "error": error_text if has_real_error else "", }