openapi: 3.0.3 info: title: 'Laravel API Documentation' description: '' version: 1.0.0 servers: - url: 'https://dev.aiadmin.quickmechs.com/admin/vehicles' tags: - name: 'API Key Management' description: "\nAPIs for managing developer API keys." - name: Authentication description: "\nAPIs for handling user login, registration and logout." - name: Endpoints description: '' - name: Predictions description: "\nEndpoints for AI-powered repair cost predictions, VIN extraction, and prediction feedback.\nAll endpoints require a valid API key in the Authorization header." paths: /api/v1/dashboard/keys: get: summary: 'List API Keys' operationId: listAPIKeys description: 'Get a list of all API keys for the authenticated user.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success data: - id: 1 name: 'My Key' public_key: pk_test_... secret_key: sk_test_... environment: test last_used_at: null properties: status: type: string example: success data: type: array example: - id: 1 name: 'My Key' public_key: pk_test_... secret_key: sk_test_... environment: test last_used_at: null items: type: object properties: id: type: integer example: 1 name: type: string example: 'My Key' public_key: type: string example: pk_test_... secret_key: type: string example: sk_test_... environment: type: string example: test last_used_at: type: string example: null nullable: true tags: - 'API Key Management' post: summary: 'Generate API Key' operationId: generateAPIKey description: 'Create a new API key for the authenticated user.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: status: success message: 'API key generated successfully...' data: id: 1 name: 'Mobile App' public_key: pk_test_... secret_key: sk_test_... environment: test properties: status: type: string example: success message: type: string example: 'API key generated successfully...' data: type: object properties: id: type: integer example: 1 name: type: string example: 'Mobile App' public_key: type: string example: pk_test_... secret_key: type: string example: sk_test_... environment: type: string example: test tags: - 'API Key Management' requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The name/label for the key.' example: 'Mobile App' environment: type: string description: 'The environment (live or test).' example: test required: - name - environment '/api/v1/dashboard/keys/{id}': delete: summary: 'Revoke API Key' operationId: revokeAPIKey description: 'Delete an API key, preventing any future access with it.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'API key revoked successfully.' properties: status: type: string example: success message: type: string example: 'API key revoked successfully.' tags: - 'API Key Management' parameters: - in: path name: id description: 'The ID of the API key to revoke.' example: 1 required: true schema: type: integer /api/v1/auth/login: post: summary: 'Authenticate User' operationId: authenticateUser description: 'Log in a user with their email and password to receive a management token.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'Authenticated successfully' data: user: id: 1 name: 'John Doe' session_token: 1|... properties: status: type: string example: success message: type: string example: 'Authenticated successfully' data: type: object properties: user: type: object properties: id: type: integer example: 1 name: type: string example: 'John Doe' session_token: type: string example: 1|... tags: - Authentication requestBody: required: true content: application/json: schema: type: object properties: email: type: string description: 'The email of the user.' example: user@example.com password: type: string description: 'The password of the user.' example: password required: - email - password security: [] /api/v1/auth/register: post: summary: 'Register User' operationId: registerUser description: 'Create a new developer account and receive a management token.' parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: status: success message: 'User registered successfully' data: user: id: 1 name: 'John Doe' session_token: 2|... properties: status: type: string example: success message: type: string example: 'User registered successfully' data: type: object properties: user: type: object properties: id: type: integer example: 1 name: type: string example: 'John Doe' session_token: type: string example: 2|... tags: - Authentication requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: 'The name of the user.' example: 'John Doe' email: type: string description: 'The email of the user.' example: john@example.com password: type: string description: 'The password (min 8 chars).' example: password required: - name - email - password security: [] /api/v1/auth/user/logout: post: summary: Logout operationId: logout description: 'Revoke the current management token.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: status: success message: 'Logged out successfully' properties: status: type: string example: success message: type: string example: 'Logged out successfully' tags: - Authentication /api/v1/admin/problems: get: summary: '' operationId: getApiV1AdminProblems description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/problems could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/problems could not be found.' tags: - Endpoints security: [] /api/v1/admin/problems/stats: get: summary: '' operationId: getApiV1AdminProblemsStats description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/problems/stats could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/problems/stats could not be found.' tags: - Endpoints security: [] '/api/v1/admin/problems/{parentId}/children': get: summary: '' operationId: getApiV1AdminProblemsParentIdChildren description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/problems/architecto/children could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/problems/architecto/children could not be found.' tags: - Endpoints security: [] parameters: - in: path name: parentId description: '' example: architecto required: true schema: type: string '/api/v1/admin/problems/{id}/show': get: summary: '' operationId: getApiV1AdminProblemsIdShow description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/problems/architecto/show could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/problems/architecto/show could not be found.' tags: - Endpoints security: [] parameters: - in: path name: id description: 'The ID of the problem.' example: architecto required: true schema: type: string '/api/v1/admin/problems/{id}/details': get: summary: '' operationId: getApiV1AdminProblemsIdDetails description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/problems/architecto/details could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/problems/architecto/details could not be found.' tags: - Endpoints security: [] parameters: - in: path name: id description: 'The ID of the problem.' example: architecto required: true schema: type: string /api/v1/admin/vehicles: get: summary: '' operationId: getApiV1AdminVehicles description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/vehicles could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/vehicles could not be found.' tags: - Endpoints security: [] post: summary: '' operationId: postApiV1AdminVehicles description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: vehicle_model_id: type: string description: 'The id of an existing record in the vehicle_models table.' example: architecto nullable: true new_make: type: string description: 'This field is required when vehicle_model_id is not present. Must not be greater than 255 characters.' example: 'n' nullable: true new_model: type: string description: 'This field is required when vehicle_model_id is not present. Must not be greater than 255 characters.' example: g nullable: true new_year: type: integer description: 'This field is required when vehicle_model_id is not present. Must be at least 1900. Must not be greater than 2100.' example: 16 nullable: true vin_mask: type: string description: 'Must be at least 11 characters. Must not be greater than 17 characters.' example: miyvdlj current_mileage: type: integer description: 'Must be at least 0.' example: 52 plate_no: type: string description: 'Must not be greater than 20 characters.' example: ikhwaykcmyuwpwlv nullable: true motor_vehicle_type: type: string description: 'Must not be greater than 255 characters.' example: q nullable: true motor_vehicle_type_group: type: string description: 'Must not be greater than 255 characters.' example: w nullable: true seed_facility_id: type: string description: 'The id of an existing record in the service_facilities table.' example: null nullable: true required: - vin_mask - current_mileage security: [] /api/v1/admin/vehicles/stats: get: summary: '' operationId: getApiV1AdminVehiclesStats description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/vehicles/stats could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/vehicles/stats could not be found.' tags: - Endpoints security: [] /api/v1/admin/vehicles/form-options: get: summary: '' operationId: getApiV1AdminVehiclesFormOptions description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/vehicles/form-options could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/vehicles/form-options could not be found.' tags: - Endpoints security: [] /api/v1/admin/vehicles/search-models: get: summary: '' operationId: getApiV1AdminVehiclesSearchModels description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/vehicles/search-models could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/vehicles/search-models could not be found.' tags: - Endpoints security: [] '/api/v1/admin/vehicles/{vehicle_id}': get: summary: '' operationId: getApiV1AdminVehiclesVehicle_id description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/vehicles/019ca9f7-adeb-731e-9b71-062301ab7efe could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/vehicles/019ca9f7-adeb-731e-9b71-062301ab7efe could not be found.' tags: - Endpoints security: [] put: summary: '' operationId: putApiV1AdminVehiclesVehicle_id description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: vin_mask: type: string description: 'Must be at least 11 characters. Must not be greater than 17 characters.' example: bngzmiy current_mileage: type: integer description: 'Must be at least 0.' example: 60 plate_no: type: string description: 'Must not be greater than 20 characters.' example: dljnikhwaykcmyuw nullable: true motor_vehicle_type: type: string description: 'Must not be greater than 255 characters.' example: p nullable: true motor_vehicle_type_group: type: string description: 'Must not be greater than 255 characters.' example: w nullable: true required: - vin_mask - current_mileage security: [] delete: summary: '' operationId: deleteApiV1AdminVehiclesVehicle_id description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: vehicle_id description: 'The ID of the vehicle.' example: 019ca9f7-adeb-731e-9b71-062301ab7efe required: true schema: type: string /api/v1/admin/regions: get: summary: '' operationId: getApiV1AdminRegions description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/regions could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/regions could not be found.' tags: - Endpoints security: [] post: summary: '' operationId: postApiV1AdminRegions description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: facility_name: type: string description: 'Must not be greater than 255 characters.' example: b city: type: string description: 'Must not be greater than 255 characters.' example: 'n' nullable: true state: type: string description: 'Must not be greater than 255 characters.' example: g nullable: true zip_code: type: string description: 'Must not be greater than 20 characters.' example: zmiyvdljnikhwayk nullable: true country: type: string description: 'Must not be greater than 255 characters.' example: c nullable: true avg_labor_rate: type: number description: 'Must be at least 0.' example: 38 nullable: true required: - facility_name security: [] /api/v1/admin/regions/stats: get: summary: '' operationId: getApiV1AdminRegionsStats description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/regions/stats could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/regions/stats could not be found.' tags: - Endpoints security: [] /api/v1/admin/regions/states: get: summary: '' operationId: getApiV1AdminRegionsStates description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/regions/states could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/regions/states could not be found.' tags: - Endpoints security: [] /api/v1/admin/regions/recalculate: post: summary: '' operationId: postApiV1AdminRegionsRecalculate description: '' parameters: [] responses: { } tags: - Endpoints security: [] '/api/v1/admin/regions/{facility_id}': get: summary: '' operationId: getApiV1AdminRegionsFacility_id description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/regions/1 could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/regions/1 could not be found.' tags: - Endpoints security: [] put: summary: '' operationId: putApiV1AdminRegionsFacility_id description: '' parameters: [] responses: { } tags: - Endpoints requestBody: required: true content: application/json: schema: type: object properties: facility_name: type: string description: 'Must not be greater than 255 characters.' example: b city: type: string description: 'Must not be greater than 255 characters.' example: 'n' nullable: true state: type: string description: 'Must not be greater than 255 characters.' example: g nullable: true zip_code: type: string description: 'Must not be greater than 20 characters.' example: zmiyvdljnikhwayk nullable: true country: type: string description: 'Must not be greater than 255 characters.' example: c nullable: true avg_labor_rate: type: number description: 'Must be at least 0.' example: 38 nullable: true required: - facility_name security: [] delete: summary: '' operationId: deleteApiV1AdminRegionsFacility_id description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: facility_id description: 'The ID of the facility.' example: 1 required: true schema: type: integer /api/v1/admin/transactions: get: summary: '' operationId: getApiV1AdminTransactions description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/transactions could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/transactions could not be found.' tags: - Endpoints security: [] post: summary: '' operationId: postApiV1AdminTransactions description: '' parameters: [] responses: { } tags: - Endpoints security: [] /api/v1/admin/transactions/stats: get: summary: '' operationId: getApiV1AdminTransactionsStats description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/transactions/stats could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/transactions/stats could not be found.' tags: - Endpoints security: [] /api/v1/admin/transactions/form-options: get: summary: '' operationId: getApiV1AdminTransactionsFormOptions description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/transactions/form-options could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/transactions/form-options could not be found.' tags: - Endpoints security: [] '/api/v1/admin/transactions/{transaction_id}': get: summary: '' operationId: getApiV1AdminTransactionsTransaction_id description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/transactions/1 could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/transactions/1 could not be found.' tags: - Endpoints security: [] put: summary: '' operationId: putApiV1AdminTransactionsTransaction_id description: '' parameters: [] responses: { } tags: - Endpoints security: [] delete: summary: '' operationId: deleteApiV1AdminTransactionsTransaction_id description: '' parameters: [] responses: { } tags: - Endpoints security: [] parameters: - in: path name: transaction_id description: 'The ID of the transaction.' example: 1 required: true schema: type: integer '/api/v1/admin/transactions/{transaction_id}/details': get: summary: '' operationId: getApiV1AdminTransactionsTransaction_idDetails description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/v1/admin/transactions/1/details could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/v1/admin/transactions/1/details could not be found.' tags: - Endpoints security: [] parameters: - in: path name: transaction_id description: 'The ID of the transaction.' example: 1 required: true schema: type: integer /api/v1/secure-data: post: summary: 'Access Secure Data' operationId: accessSecureData description: "This endpoint is protected by the API Key middleware.\nYou must provide a valid secret key in the Authorization header." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: message: 'Secure data accessed successfully' api_key_used: 'My Key' properties: message: type: string example: 'Secure data accessed successfully' api_key_used: type: string example: 'My Key' tags: - Endpoints /api/user: get: summary: '' operationId: getApiUser description: '' parameters: [] responses: 404: description: '' content: application/json: schema: type: object example: message: 'The route admin/vehicles/api/user could not be found.' properties: message: type: string example: 'The route admin/vehicles/api/user could not be found.' tags: - Endpoints security: [] /api/v1/predict: post: summary: 'Get Repair Cost Prediction' operationId: getRepairCostPrediction description: "Calculates a repair price estimate using local historical data combined with\nAI predictions from Gemini and DeepSeek. Results are cached for 3 days using\na memory decay system (100% fresh → 0% at expiry)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true session_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 memory_source: fresh memory_decay_remaining: 100.0 memory_expires_at: '2026-03-08T12:00:00+00:00' red_flag: false red_flag_reason: null match_percentage: 87.5 aggregated_ai_average: 450.0 local_prediction: average_total_estimate: 425.5 low_total_estimate: 350.0 high_total_estimate: 500.0 gemini_prediction: ai_average_estimate: 460.0 match_percentage: 92.0 deepseek_prediction: ai_average_estimate: 440.0 match_percentage: 96.5 repair_breakdown: source: local_scaled parts: - name: 'Brake Pad Set' unit_price: 45.0 quantity: 2 total_price: 90.0 estimated_labor_hours: 1.5 total_parts_cost: 90.0 total_estimate: 425.5 properties: success: type: boolean example: true session_id: type: string example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 memory_source: type: string example: fresh memory_decay_remaining: type: number example: 100.0 memory_expires_at: type: string example: '2026-03-08T12:00:00+00:00' red_flag: type: boolean example: false red_flag_reason: type: string example: null nullable: true match_percentage: type: number example: 87.5 aggregated_ai_average: type: number example: 450.0 local_prediction: type: object properties: average_total_estimate: type: number example: 425.5 low_total_estimate: type: number example: 350.0 high_total_estimate: type: number example: 500.0 gemini_prediction: type: object properties: ai_average_estimate: type: number example: 460.0 match_percentage: type: number example: 92.0 deepseek_prediction: type: object properties: ai_average_estimate: type: number example: 440.0 match_percentage: type: number example: 96.5 repair_breakdown: type: object properties: source: type: string example: local_scaled parts: type: array example: - name: 'Brake Pad Set' unit_price: 45 quantity: 2 total_price: 90 items: type: object properties: name: type: string example: 'Brake Pad Set' unit_price: type: number example: 45.0 quantity: type: integer example: 2 total_price: type: number example: 90.0 estimated_labor_hours: type: number example: 1.5 total_parts_cost: type: number example: 90.0 total_estimate: type: number example: 425.5 404: description: '' content: application/json: schema: type: object example: success: false message: 'Vehicle not found based on the provided VIN.' error_code: VEHICLE_NOT_FOUND properties: success: type: boolean example: false message: type: string example: 'Vehicle not found based on the provided VIN.' error_code: type: string example: VEHICLE_NOT_FOUND 500: description: '' content: application/json: schema: type: object example: success: false message: 'An error occurred while calculating the estimate.' error_details: 'Error message here' properties: success: type: boolean example: false message: type: string example: 'An error occurred while calculating the estimate.' error_details: type: string example: 'Error message here' tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: vin: type: string description: 'The vehicle VIN (11 or 17 characters).' example: 1HGBH41JXMN109186 zip_code: type: string description: 'The zip code for regional pricing.' example: '90210' problem_identifier: type: string description: 'The problem category ID or identifier.' example: '42' required: - vin - zip_code - problem_identifier /api/v1/predict/problems: post: summary: 'Get Problem Identifiers' operationId: getProblemIdentifiers description: "Fetches available problem categories for a vehicle's group based on its VIN.\nReturns hierarchical category names (Parent > Child) that can be used as the\n`problem_identifier` parameter in the predict endpoint." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 42 display_name: 'Brakes > Brake Pad Replacement' - id: 15 display_name: 'Engine > Oil Change' - id: 78 display_name: 'Suspension > Shock Absorber' properties: success: type: boolean example: true data: type: array example: - id: 42 display_name: 'Brakes > Brake Pad Replacement' - id: 15 display_name: 'Engine > Oil Change' - id: 78 display_name: 'Suspension > Shock Absorber' items: type: object properties: id: type: integer example: 42 display_name: type: string example: 'Brakes > Brake Pad Replacement' 404: description: '' content: application/json: schema: type: object example: success: false message: 'Vehicle not found based on the provided VIN.' error_code: VEHICLE_NOT_FOUND properties: success: type: boolean example: false message: type: string example: 'Vehicle not found based on the provided VIN.' error_code: type: string example: VEHICLE_NOT_FOUND 500: description: '' content: application/json: schema: type: object example: success: false message: 'An error occurred while fetching problems.' error_details: 'Error message here' properties: success: type: boolean example: false message: type: string example: 'An error occurred while fetching problems.' error_details: type: string example: 'Error message here' tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: vin: type: string description: 'The vehicle VIN (11 or 17 characters).' example: 1HGBH41JXMN109186 required: - vin /api/v1/predict/categories: get: summary: 'List Problem Categories (Main)' operationId: listProblemCategoriesMain description: 'Returns all top-level (parent) problem identifier categories.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 1 name: Brakes description: 'Brake system issues' - id: 2 name: Engine description: 'Engine related problems' properties: success: type: boolean example: true data: type: array example: - id: 1 name: Brakes description: 'Brake system issues' - id: 2 name: Engine description: 'Engine related problems' items: type: object properties: id: type: integer example: 1 name: type: string example: Brakes description: type: string example: 'Brake system issues' tags: - Predictions '/api/v1/predict/categories/{parentId}/sub': get: summary: 'List Sub-Categories' operationId: listSubCategories description: 'Returns all child problem identifier categories under a given main category.' parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 10 name: 'Brake Pad Replacement' description: null - id: 11 name: 'Brake Rotor Replacement' description: null properties: success: type: boolean example: true data: type: array example: - id: 10 name: 'Brake Pad Replacement' description: null - id: 11 name: 'Brake Rotor Replacement' description: null items: type: object properties: id: type: integer example: 10 name: type: string example: 'Brake Pad Replacement' description: type: string example: null nullable: true 404: description: '' content: application/json: schema: type: object example: success: false message: 'Main category not found.' properties: success: type: boolean example: false message: type: string example: 'Main category not found.' tags: - Predictions parameters: - in: path name: parentId description: 'The ID of the main category.' example: 1 required: true schema: type: integer /api/v1/predict/red-flags: get: summary: 'Get Red Flags / Prediction History' operationId: getRedFlagsPredictionHistory description: "Returns the most recent 50 predictions with red flag analysis and feedback counts.\nAdmins see all predictions; regular users see only their own." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: - id: 1 session_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 vin: 1HGBH41JXMN109186 problem_name: 'Brakes > Brake Pad Replacement' red_flag: true red_flag_reason: 'Local estimate appears unrealistically low compared to the aggregated AI prediction.' match_percentage: 45.2 local_average_estimate: 150.0 ai_average_estimate: 450.0 feedbacks_count: 3 good_feedbacks_count: 2 created_at: '2026-03-05T10:30:00.000000Z' properties: success: type: boolean example: true data: type: array example: - id: 1 session_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 vin: 1HGBH41JXMN109186 problem_name: 'Brakes > Brake Pad Replacement' red_flag: true red_flag_reason: 'Local estimate appears unrealistically low compared to the aggregated AI prediction.' match_percentage: 45.2 local_average_estimate: 150 ai_average_estimate: 450 feedbacks_count: 3 good_feedbacks_count: 2 created_at: '2026-03-05T10:30:00.000000Z' items: type: object properties: id: type: integer example: 1 session_id: type: string example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 vin: type: string example: 1HGBH41JXMN109186 problem_name: type: string example: 'Brakes > Brake Pad Replacement' red_flag: type: boolean example: true red_flag_reason: type: string example: 'Local estimate appears unrealistically low compared to the aggregated AI prediction.' match_percentage: type: number example: 45.2 local_average_estimate: type: number example: 150.0 ai_average_estimate: type: number example: 450.0 feedbacks_count: type: integer example: 3 good_feedbacks_count: type: integer example: 2 created_at: type: string example: '2026-03-05T10:30:00.000000Z' tags: - Predictions /api/v1/predict/extract-vin: post: summary: 'Extract VIN from Image' operationId: extractVINFromImage description: "Uses Gemini AI vision to extract a 17-character VIN from an uploaded image.\nSupports photos of VIN plates, stickers, dashboards, and registration documents." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true vin: 1HGBH41JXMN109186 message: 'VIN extracted successfully' properties: success: type: boolean example: true vin: type: string example: 1HGBH41JXMN109186 message: type: string example: 'VIN extracted successfully' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Could not detect a valid 17-character VIN in the provided image.' properties: success: type: boolean example: false message: type: string example: 'Could not detect a valid 17-character VIN in the provided image.' 500: description: '' content: application/json: schema: type: object example: success: false message: 'An error occurred during AI image processing.' error_details: 'Error message here' properties: success: type: boolean example: false message: type: string example: 'An error occurred during AI image processing.' error_details: type: string example: 'Error message here' tags: - Predictions requestBody: required: true content: multipart/form-data: schema: type: object properties: image: type: string format: binary description: 'The image file containing a VIN. Max 10MB. Allowed types: jpeg, png, jpg, webp.' required: - image /api/v1/predict/plate-to-vin: post: summary: 'Resolve VIN from License Plate' operationId: resolveVINFromLicensePlate description: "Looks up a US license plate to get the VIN, then runs it through the\nexisting VIN flow (NHTSA decode, API-Ninjas enrichment, vehicle creation)." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true vin: 1C4PJMCS6EW221428 plate: TESTPLATE1 state: CA vehicle: id: 019cd1d5-3003-7069-a439-eddb9f25914d display_name: '2014 Jeep Cherokee Limited 3.2 L 271 HP ...' motor_vehicle_type: Truck motor_vehicle_type_group: 'Light Duty' message: 'VIN resolved from plate successfully' properties: success: type: boolean example: true vin: type: string example: 1C4PJMCS6EW221428 plate: type: string example: TESTPLATE1 state: type: string example: CA vehicle: type: object properties: id: type: string example: 019cd1d5-3003-7069-a439-eddb9f25914d display_name: type: string example: '2014 Jeep Cherokee Limited 3.2 L 271 HP ...' motor_vehicle_type: type: string example: Truck motor_vehicle_type_group: type: string example: 'Light Duty' message: type: string example: 'VIN resolved from plate successfully' 422: description: '' content: application/json: schema: type: object example: success: false message: 'Could not resolve a VIN from the provided license plate.' properties: success: type: boolean example: false message: type: string example: 'Could not resolve a VIN from the provided license plate.' tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: plate: type: string description: 'The license plate number.' example: TESTPLATE1 state: type: string description: 'The 2-letter US state code.' example: CA required: - plate - state /api/v1/predict/vehicle-lookup: post: summary: 'Vehicle Lookup by VIN' operationId: vehicleLookupByVIN description: "Returns basic vehicle info (display name, make, model, year, plate number) for a given VIN.\nIf the VIN is not in the database, it will be decoded via NHTSA and created." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true data: vin: 1GNCT18XX5K000000 display_name: '2005 Chevrolet Equinox LT 3.4 L 185 HP ...' make: Chevrolet model: Equinox year: 2005 plate_no: ABC1234 properties: success: type: boolean example: true data: type: object properties: vin: type: string example: 1GNCT18XX5K000000 display_name: type: string example: '2005 Chevrolet Equinox LT 3.4 L 185 HP ...' make: type: string example: Chevrolet model: type: string example: Equinox year: type: integer example: 2005 plate_no: type: string example: ABC1234 422: description: '' content: application/json: schema: type: object example: success: false message: 'Could not decode this VIN.' properties: success: type: boolean example: false message: type: string example: 'Could not decode this VIN.' tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: vin: type: string description: 'The VIN number (11-17 characters).' example: 1GNCT18XX5K000000 required: - vin /api/v1/predict/by-specs: post: summary: 'Predict by Vehicle Specs' operationId: predictByVehicleSpecs description: "Calculates a repair cost prediction using year/make/model instead of a VIN.\nSearches the database for matching vehicles, optionally narrowed by trim and engine.\nIf no match is found, creates a spec-based vehicle using API-Ninjas for enrichment.\nThen runs the same prediction flow as the VIN-based endpoint." parameters: [] responses: 200: description: '' content: text/plain: schema: type: string example: "{\n \"success\": true,\n \"session_id\": \"a1b2c3d4-e5f6-7890-abcd-ef1234567890\",\n \"vehicle_match\": {\n \"source\": \"database\",\n \"matched_count\": 12,\n \"vehicle_used\": {\n \"id\": \"...\",\n \"vin\": \"1C6RR6GT2GS******\",\n \"display_name\": \"2016 Ram 1500 SLT 5.7 L 395 HP V 8 (T) GAS FI - EZH - A\"\n }\n },\n \"local_prediction\": { \"...\" },\n \"gemini_prediction\": { \"...\" },\n \"deepseek_prediction\": { \"...\" },\n \"repair_breakdown\": { \"...\" }\n}" 404: description: '' content: application/json: schema: type: object example: success: false message: 'No vehicles found for the provided specs and could not create one.' properties: success: type: boolean example: false message: type: string example: 'No vehicles found for the provided specs and could not create one.' tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: year: type: integer description: 'The vehicle year.' example: 2016 make: type: string description: 'The vehicle make.' example: Ram model: type: string description: 'The vehicle model.' example: '1500' trim: type: string description: 'optional The vehicle trim.' example: SLT nullable: true engine: type: string description: 'optional Engine displacement (e.g. "5.7").' example: '5.7' nullable: true zip_code: type: string description: 'The zip code for regional pricing.' example: '90210' problem_identifier: type: string description: 'The problem category ID or identifier.' example: '42' required: - year - make - model - zip_code - problem_identifier /api/v1/predict/makes: get: summary: 'Get Available Makes' operationId: getAvailableMakes description: "Returns all distinct vehicle makes in the database, sorted alphabetically.\nOptionally filter by year to only show makes available for that year." parameters: - in: query name: year description: 'Optional year to filter makes.' example: 2016 required: false schema: type: integer description: 'Optional year to filter makes.' example: 2016 responses: 200: description: '' content: application/json: schema: type: object example: success: true count: 45 data: - Acura - BMW - Chevrolet - Dodge - Ford - ... properties: success: type: boolean example: true count: type: integer example: 45 data: type: array example: - Acura - BMW - Chevrolet - Dodge - Ford - ... items: type: string tags: - Predictions /api/v1/predict/models: get: summary: 'Get Available Models' operationId: getAvailableModels description: "Returns all distinct vehicle models for a given make.\nOptionally filter by year." parameters: - in: query name: make description: 'The vehicle make.' example: Chevrolet required: true schema: type: string description: 'The vehicle make.' example: Chevrolet - in: query name: year description: 'Optional year to filter models.' example: 2016 required: false schema: type: integer description: 'Optional year to filter models.' example: 2016 responses: 200: description: '' content: application/json: schema: type: object example: success: true count: 12 data: - Camaro - Corvette - Equinox - Malibu - 'Silverado 1500' - ... properties: success: type: boolean example: true count: type: integer example: 12 data: type: array example: - Camaro - Corvette - Equinox - Malibu - 'Silverado 1500' - ... items: type: string tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: make: type: string description: 'Must not be greater than 100 characters.' example: b required: - make /api/v1/predict/trims: get: summary: 'Get Available Trims' operationId: getAvailableTrims description: "Returns all distinct trims for a given make, model, and year.\nParsed from the vehicle display_name field." parameters: - in: query name: make description: 'The vehicle make.' example: Chevrolet required: true schema: type: string description: 'The vehicle make.' example: Chevrolet - in: query name: model description: 'The vehicle model.' example: Camaro required: true schema: type: string description: 'The vehicle model.' example: Camaro - in: query name: year description: 'The vehicle year.' example: 2016 required: true schema: type: integer description: 'The vehicle year.' example: 2016 responses: 200: description: '' content: application/json: schema: type: object example: success: true count: 3 data: - LT - SS - ZL1 properties: success: type: boolean example: true count: type: integer example: 3 data: type: array example: - LT - SS - ZL1 items: type: string tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: make: type: string description: 'Must not be greater than 100 characters.' example: b model: type: string description: 'Must not be greater than 100 characters.' example: 'n' year: type: integer description: 'Must be at least 1900. Must not be greater than 2100.' example: 7 required: - make - model - year /api/v1/predict/engines: get: summary: 'Get Available Engines' operationId: getAvailableEngines description: "Returns all distinct engine configurations for a given make, model, and year.\nOptionally filter by trim. Parsed from the vehicle display_name field." parameters: - in: query name: make description: 'The vehicle make.' example: Chevrolet required: true schema: type: string description: 'The vehicle make.' example: Chevrolet - in: query name: model description: 'The vehicle model.' example: Camaro required: true schema: type: string description: 'The vehicle model.' example: Camaro - in: query name: year description: 'The vehicle year.' example: 2016 required: true schema: type: integer description: 'The vehicle year.' example: 2016 - in: query name: trim description: 'optional Filter by trim.' example: SS required: false schema: type: string description: 'optional Filter by trim.' example: SS responses: 200: description: '' content: application/json: schema: type: object example: success: true count: 2 data: - displacement: '3.6' hp: '335' cylinders: 'V 6' fuel: GAS - displacement: '6.2' hp: '455' cylinders: 'V 8' fuel: GAS properties: success: type: boolean example: true count: type: integer example: 2 data: type: array example: - displacement: '3.6' hp: '335' cylinders: 'V 6' fuel: GAS - displacement: '6.2' hp: '455' cylinders: 'V 8' fuel: GAS items: type: object properties: displacement: type: string example: '3.6' hp: type: string example: '335' cylinders: type: string example: 'V 6' fuel: type: string example: GAS tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: make: type: string description: 'Must not be greater than 100 characters.' example: b model: type: string description: 'Must not be greater than 100 characters.' example: 'n' year: type: integer description: 'Must be at least 1900. Must not be greater than 2100.' example: 7 trim: type: string description: 'Must not be greater than 100 characters.' example: z nullable: true required: - make - model - year /api/v1/predict/feedback: post: summary: 'Submit Prediction Feedback' operationId: submitPredictionFeedback description: "Allows users to rate a prediction as \"good\" or \"wrong\" with an optional comment.\nAdmins can submit feedback on any prediction; regular users only on their own." parameters: [] responses: 201: description: '' content: application/json: schema: type: object example: success: true message: 'Feedback submitted successfully.' data: id: 1 prediction_history_id: 42 rating: good comment: 'Price was accurate for my area.' created_at: '2026-03-05T12:00:00.000000Z' properties: success: type: boolean example: true message: type: string example: 'Feedback submitted successfully.' data: type: object properties: id: type: integer example: 1 prediction_history_id: type: integer example: 42 rating: type: string example: good comment: type: string example: 'Price was accurate for my area.' created_at: type: string example: '2026-03-05T12:00:00.000000Z' 422: description: '' content: application/json: schema: type: object example: message: 'The given data was invalid.' errors: session_id: - 'The selected session id is invalid.' properties: message: type: string example: 'The given data was invalid.' errors: type: object properties: session_id: type: array example: - 'The selected session id is invalid.' items: type: string tags: - Predictions requestBody: required: true content: application/json: schema: type: object properties: session_id: type: string description: 'The UUID session ID of the prediction.' example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 rating: type: string description: 'The rating value. Must be "good" or "wrong".' example: good comment: type: string description: 'Optional feedback comment (max 1000 chars).' example: 'Price was accurate for my area.' nullable: true required: - session_id - rating '/api/v1/predict/feedback/{session_id}': get: summary: 'Get Feedback Stats' operationId: getFeedbackStats description: "Returns feedback statistics and all feedback entries for a prediction.\nIncludes total count, good/wrong breakdown, and a calculated feedback score (0-100%).\nAdmins can view any prediction's feedback; regular users only their own." parameters: [] responses: 200: description: '' content: application/json: schema: type: object example: success: true session_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890 total_feedbacks: 5 good_count: 4 wrong_count: 1 feedback_score: 80.0 feedbacks: - id: 1 rating: good comment: 'Very accurate!' created_at: '2026-03-05T12:00:00.000000Z' properties: success: type: boolean example: true session_id: type: string example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 total_feedbacks: type: integer example: 5 good_count: type: integer example: 4 wrong_count: type: integer example: 1 feedback_score: type: number example: 80.0 feedbacks: type: array example: - id: 1 rating: good comment: 'Very accurate!' created_at: '2026-03-05T12:00:00.000000Z' items: type: object properties: id: type: integer example: 1 rating: type: string example: good comment: type: string example: 'Very accurate!' created_at: type: string example: '2026-03-05T12:00:00.000000Z' 404: description: '' content: application/json: schema: type: object example: message: 'No query results for model [App\Models\PredictionHistory].' properties: message: type: string example: 'No query results for model [App\Models\PredictionHistory].' tags: - Predictions parameters: - in: path name: session_id description: 'The UUID session ID of the prediction.' example: a1b2c3d4-e5f6-7890-abcd-ef1234567890 required: true schema: type: string