{"openapi":"3.0.0","info":{"title":"API REST Taller GP","description":"\n# Introduction\nDescripción de las características del API de TallerGP. Introducción de texto comentando las funcionalidades o temas relevantes, como la solicitud de acceso al API\n# \n# Authorization\nSolicitar a soporte de TallerGP la generación de un client_id y client_secret para poder obtener un ```access_token``` con el que poder realizar las solicitudes al servicio.\n\n***Autorizar llamadas al API*** \n- GET,POST,PUT,DELETE requests, add ***Authorization*** to your header.\n``` Authorization: Bearer ACCESS_TOKEN ```\n","version":"1.0.20","x-versionDate":"2026-09-24","contact":{"email":"info@tallergp.com","name":"Soporte TallerGP"},"license":{"name":"Creative Commons","url":"https://creativecommons.org/licenses/by/4.0/legalcode"}},"servers":[{"url":"https://api.tallergp.com","description":"TallerGP Api REST"}],"security":[{"Bearer":[]}],"tags":[{"name":"Clientes","x-parentTag":"Gestión"},{"name":"Proveedores","x-parentTag":"Gestión"},{"name":"Empleados","x-parentTag":"Gestión"},{"name":"Aseguradoras","x-parentTag":"Gestión"},{"name":"Usuarios","x-parentTag":"Gestión"},{"name":"Resguardos","x-parentTag":"Taller"},{"name":"Presupuestos","x-parentTag":"Taller"},{"name":"Ordenes","x-parentTag":"Taller"},{"name":"Facturas","x-parentTag":"Taller"},{"name":"Materiales","x-parentTag":"Almacén"},{"name":"Albaranes de Compra","x-parentTag":"Almacén"},{"name":"Facturas de Compra","x-parentTag":"Almacén"},{"name":"Neumáticos","x-parentTag":"Almacén"},{"name":"Citas","x-parentTag":"Planificación"},{"name":"Notificaciones","x-parentTag":"Planificación"},{"name":"Marcas y modelos","x-parentTag":"Tablas Maestras"},{"name":"Tipos de fichaje","x-parentTag":"Tablas Maestras"},{"name":"Tipos de cita","x-parentTag":"Tablas Maestras"}],"paths":{"/customers":{"get":{"summary":"Obtiene todos los clientes del taller con paginación.","description":"Devuelve un listado paginado de clientes asociados al taller autenticado. Soporta paginación y ordenación mediante parámetros de consulta","operationId":"readCustomers","tags":["Clientes"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página","schema":{"type":"integer"}},{"name":"customer_number","in":"query","required":false,"description":"Número de cliente","schema":{"type":"string"}},{"name":"email","in":"query","required":false,"description":"Filtrar por email (busqueda parcial).","schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"description":"Teléfono del cliente","schema":{"type":"string"}}],"responses":{"200":{"description":"List of customers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetClientesListResponse"}}}},"401":{"description":"Failed to generate customers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqoz000kzvnejnrpusfb","x-order":0,"security":[{"Bearer":[]}]},"post":{"summary":"Crea un nuevo cliente en el sistema","description":"Registra un nuevo cliente asociado al taller del token de autenticación.\n\n## Campos requeridos\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `name` | string | Nombre del cliente |\n| `customer_number` | string | Identificador externo |\n\n## Campos opcionales principales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `lastname` | string | Primer apellido |\n| `surname` | string | Segundo apellido |\n| `phone` | string | Teléfono fijo |\n| `mobile` | string | Teléfono móvil |\n| `mail` | string | Correo electrónico |\n| `vat_number` | string | NIF/CIF |\n| `address` | string | Dirección |\n| `zip_code` | string | Código postal |\n| `location` | string | Población |\n| `province` | string | Provincia |\n\n## Campos opcionales comerciales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `customer_number` | string | Número de cliente (manual) |\n| `alias` | string | Alias o nombre comercial |\n| `observations` | string | Observaciones |\n| `parts_discount` | float | Descuento en piezas (%) |\n| `labor_discount` | float | Descuento en mano de obra (%) |\n| `general_discount` | float | Descuento general (%) |\n| `blocked` | boolean | Cliente bloqueado |\n\n## Campos auto-generados\n\n- `id` — Identificador único del cliente (UNIQUE_ID)\n- Asociación al taller del token de autenticación","tags":["Clientes"],"responses":{"200":{"description":"Respuesta exitosa"}},"x-endpoint-id":"cmkw8crzn0003qub145fv14c1","x-order":8,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewCustomer"},"example":{"name":"Juan","customer_number":"CLI001","lastname":"Pérez","surname":"García","phone":"961234567","mobile":"612345678","mail":"juan@example.com","vat_number":"12345678A","address":"Calle Mayor 1","zip_code":"46001","location":"Valencia","province":"Valencia"}}}},"security":[{"Bearer":[]}]}},"/vehicle-intakes":{"get":{"summary":"Listado de resguardos","description":"Obtiene un listado paginado de resguardos (entradas de vehículos).","operationId":"listVehicleIntakes","tags":["Resguardos"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer"}},{"name":"from_date","in":"query","required":false,"description":"Fecha desde (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"to_date","in":"query","required":false,"description":"Fecha hasta (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"client_id","in":"query","required":false,"description":"Identificador único de cliente","schema":{"type":"string"}},{"name":"vehicle_id","in":"query","required":false,"description":"Identificador único de vehículo","schema":{"type":"string"}},{"name":"intake_number","in":"query","required":false,"description":"Número de resguardo (coincidencia exacta)","schema":{"type":"string"}},{"name":"plate","in":"query","required":false,"description":"Matrícula del vehículo (coincidencia parcial)","schema":{"type":"string"}},{"name":"status_code","in":"query","required":false,"description":"Estado del resguardo: 1=Abierto, 2=Cerrado","schema":{"type":"integer"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeListResponse"},"example":{"pagination":{"current_page":1,"per_page":10,"total_count":25,"total_pages":3},"data":[{"id":"es6b4l40ic7sfk3pqw0sfay6y39bt9w0","intake_number":"0000000025","entry_date":"20/02/2026","client_id":"7ps4717hwaukddngvbom3f5yjf54q7q1","vehicle_id":"9g38jrhu52oj5f5vp3ivmr1gxn2wqr1h","plate":"2964-KBP","km":"70000","status_code":1,"status_name":"Abierto","status_color":"#3cb371","depositor_name":"Juan deposita","estimated_date":"24/02/2026","is_blocked":false,"is_archived":false},{"id":"es6wye0z2sjxf1ph2uo3pyvp4qpl8q79","intake_number":"0000000024","entry_date":"10/06/2025","client_id":"7ps4717hwaukddngvbom3f5yjf54q7q1","vehicle_id":"9g38jrhu52oj5f5vp3ivmr1gxn2wqr1h","plate":"2964-KBP","km":"2222","status_code":1,"status_name":"Abierto","status_color":"#3cb371","depositor_name":null,"estimated_date":null,"is_blocked":false,"is_archived":false},{"id":"es6lvbkkkvm7t472nxj27bumk5ggl8p8","intake_number":"0000000023","entry_date":"10/06/2025","client_id":"7ps4717hwaukddngvbom3f5yjf54q7q1","vehicle_id":"9g38jrhu52oj5f5vp3ivmr1gxn2wqr1h","plate":"2964-KBP","km":"22222","status_code":2,"status_name":"Cerrado","status_color":"#808080","depositor_name":null,"estimated_date":null,"is_blocked":false,"is_archived":false}]}}}}},"x-endpoint-id":"ik_ep_l","x-order":1,"security":[{"Bearer":[]}]},"post":{"summary":"Crear resguardo","description":"Crea un resguardo de deposito. Son obligatorios `client_id` y `vehicle_id` (los identificadores que devuelven los listados de clientes y vehiculos); `insurer_id` es el identificador del listado de aseguradoras. El identificador y el numero de resguardo se generan automaticamente (el numero sigue la serie del taller) y el resguardo se crea en estado Abierto. Si no se envia `entry_date`, se usa la fecha actual. Las fechas van en formato DD/MM/YYYY. Devuelve el resguardo creado.","operationId":"createVehicleIntake","tags":["Resguardos"],"responses":{"201":{"description":"Resguardo creado con exito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeResponse"}}}},"400":{"description":"Datos invalidos (p. ej. falta client_id o vehicle_id, o no existen para el taller).","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["client_id is required","vehicle_id is required"]}}}},"401":{"description":"Token no valido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}}},"x-endpoint-id":"ep_intake_post","x-order":5,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeCreateRequest"}}}},"security":[{"Bearer":[]}]}},"/customers/{client_id}":{"get":{"summary":"Obtener información del cliente.","description":"Devuelve el detalle completo de un cliente del taller autenticado identificado por su client_id. Si el cliente no existe o no pertenece al taller, se devolverá un error 404","tags":["Clientes"],"parameters":[{"name":"client_id","in":"path","required":true,"description":"Identificador único del cliente.","schema":{"type":"string"}}],"responses":{"200":{"description":"Datos del cliente obtenidos con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerDetail"}}}},"400":{"description":"Error en los parámetros de la solicitud.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Descripción del error."}}}}}},"404":{"description":"Cliente no encontrado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerNotFound"}}}}},"x-endpoint-id":"cminveqp8001czvne5lk8umn3","x-order":2,"security":[{"Bearer":[]}]},"put":{"summary":"Actualiza un cliente existente","description":"Actualiza los datos de un cliente existente asociado al taller del token de autenticación.\n\n## Validaciones\n\n- **Número de cliente único**: No puede existir otro cliente con el mismo número en el taller\n- **CIF/NIF único**: No puede existir otro cliente con el mismo CIF/NIF en el taller\n\n## Campos actualizables principales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `name` | string | Nombre del cliente |\n| `lastname` | string | Primer apellido |\n| `surname` | string | Segundo apellido |\n| `customer_number` | string | Número de cliente |\n| `vat_number` | string | NIF/CIF |\n\n## Campos de contacto\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `phone` | string | Teléfono fijo |\n| `mobile` | string | Teléfono móvil |\n| `mail` | string | Correo electrónico |\n| `address` | string | Dirección |\n| `zip_code` | string | Código postal |\n| `location` | string | Población |\n| `province` | string | Provincia |\n\n## Campos comerciales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `alias` | string | Alias o nombre comercial |\n| `observations` | string | Observaciones |\n| `parts_discount` | float | Descuento en piezas (%) |\n| `labor_discount` | float | Descuento en mano de obra (%) |\n| `general_discount` | float | Descuento general (%) |\n| `blocked` | boolean | Cliente bloqueado |\n\n## Notas\n\n- Solo se actualizan los campos enviados en el body\n- La comparación de número/CIF se hace normalizada (mayúsculas, sin espacios ni caracteres especiales)","operationId":"updateCustomer","tags":["Clientes"],"parameters":[{"name":"client_id","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}},"x-endpoint-id":"ep_customer_put_001","x-order":9,"requestBody":{"required":false,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewCustomer"},"example":{"name":"Juan Actualizado","mobile":"622345678","mail":"juan.nuevo@example.com","observations":"Cliente preferente"}}}}}},"/vehicle-intakes/{intake_id}":{"get":{"summary":"Detalle de resguardo","description":"Obtiene el detalle completo de un resguardo por su identificador único.","operationId":"getVehicleIntake","tags":["Resguardos"],"parameters":[{"name":"intake_id","in":"path","required":true,"description":"Identificador único del resguardo","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeDetailResponse"},"example":{"id":"es6b4l40ic7sfk3pqw0sfay6y39bt9w0","intake_number":"0000000025","entry_date":"20/02/2026","client_id":"7ps4717hwaukddngvbom3f5yjf54q7q1","vehicle_id":"9g38jrhu52oj5f5vp3ivmr1gxn2wqr1h","plate":"2964-KBP","km":"70000","status_code":1,"status_name":"Abierto","status_color":"#3cb371","depositor_name":"Juan deposita","estimated_date":"24/02/2026","is_blocked":false,"is_archived":false,"observations":"Aleta izquierda, revisión itv","internal_observations":"Debe una factura ","acceptance_code":null,"siniester_number":null,"insurance_amount":0,"next_itv_date":null,"send_date":null,"has_parts_reception":true,"important_notice":true,"employee_name":"RUBÉN","fuel_level_code":2,"fuel_level_name":"1/2 deposito","insurer_id":null,"bill_to_client_id":null,"billing_group_name":"mecanica"}}}}},"x-endpoint-id":"ik_ep_d","x-order":3,"security":[{"Bearer":[]}]},"put":{"summary":"Actualizar resguardo","description":"Actualiza los datos de un resguardo existente. Solo se modifican los campos enviados en el cuerpo. Con `status_code` se puede cerrar (2) o reabrir (1) el resguardo. Devuelve el resguardo actualizado.","operationId":"updateVehicleIntake","tags":["Resguardos"],"parameters":[{"name":"intake_id","in":"path","required":true,"description":"Identificador unico del resguardo.","schema":{"type":"string"}}],"responses":{"200":{"description":"Resguardo actualizado con exito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeResponse"}}}},"400":{"description":"Datos invalidos o sin campos que actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["status_code must be 1 (open) or 2 (closed)"]}}}},"401":{"description":"Token no valido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}},"404":{"description":"Resguardo no encontrado.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Vehicle intake not found"}}}}}},"x-endpoint-id":"ep_intake_put","x-order":7,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeUpdateRequest"}}}},"security":[{"Bearer":[]}]}},"/customers/{client_id}/vehicles":{"get":{"summary":"Obtener los vehículos de un cliente","description":"Devuelve el listado paginado de vehículos asociados a un cliente del taller autenticado identificado por su client_id.","tags":["Clientes"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer","default":10}},{"name":"client_id","in":"path","required":true,"description":"Identificador único del cliente.","schema":{"type":"string"}}],"responses":{"200":{"description":"Datos obtenidos con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetCustomerVehiclesResponse"}}}},"400":{"description":"Error en los parámetros de la solicitud.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Descripción del error."}}}}}},"404":{"description":"Cliente no encontrado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerNotFound"}}}}},"x-endpoint-id":"cminveqpf0020zvnextox6qvj","x-order":4,"security":[{"Bearer":[]}]}},"/customers/{client_id}/vehicles/{vehicle_id}":{"get":{"summary":"Obtener los vehículos de un cliente","description":"Devuelve el detalle de un vehículo asociado a un cliente del taller autenticado identificado por su client_id y vehicle_id. Si el cliente o el vehículo no existen, o no pertenecen al taller autenticado, se devolverá un error 404.","tags":["Clientes"],"parameters":[{"name":"client_id","in":"path","required":true,"description":"Identificador único del cliente.","schema":{"type":"string"}},{"name":"vehicle_id","in":"path","required":true,"description":"Identificador único del vehículo","schema":{"type":"string"}}],"responses":{"200":{"description":"Datos del vehiculo obtenidos con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerVehicleDetail"}}}},"400":{"description":"Error en los parámetros de la solicitud.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"Descripción del error."}}}}}},"404":{"description":"Cliente no encontrado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerNotFound"}}}}},"x-endpoint-id":"cminveqpo002wzvney709yx12","x-order":6,"security":[{"Bearer":[]}]}},"/vehicles":{"get":{"summary":"Listado de vehículos del taller","description":"Devuelve un listado paginado de vehículos del taller autenticado.\n\n---\n\n### Parámetros de query\n\n| Parámetro | Tipo | Descripción |\n|----------|------|-------------|\n| `page` | integer | Número de página |\n| `per_page` | integer | Número de elementos por página |\n| `plate` | string | Matrícula del vehículo |\n| `vin` | string | Número de bastidor del vehículo (VIN) |  \n\n---\n\n### Datos devueltos\n\n| Campo | Tipo | Descripción |\n|------|------|-------------|\n| `current_page` | integer | Página actual |\n| `per_page` | integer | Elementos por página |\n| `total` | integer | Total de vehículos |\n| `total_pages` | integer | Total de páginas |\n\n### Listado de vehículos\n\n| Campo | Tipo | Descripción |\n|------|------|-------------|\n| `id` | string | Identificador único |\n| `plate` | string | Matrícula |\n| `vin` | string | Bastidor (VIN) |\n| `brand` | string | Marca |\n| `model` | string | Modelo |\n| `client_id` | string | ID del cliente asociado |\n","tags":["Clientes"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de registros por página","schema":{"type":"integer"}},{"name":"plate","in":"query","required":false,"description":"Matrícula del vehículo","schema":{"type":"string"}},{"name":"vat","in":"query","required":false,"description":"Número de bastidor del vehículo","schema":{"type":"string"}}],"responses":{"200":{"description":"Respuesta exitosa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Vehicle"}}}}},"x-endpoint-id":"cmkyn95ys000ko1cll8x7srhl","x-order":10,"security":[{"Bearer":[]}]},"post":{"summary":"Crea un nuevo vehículo asociado a un cliente","description":"Registra un nuevo vehículo en el sistema, asociándolo a un cliente existente y al taller del token de autenticación.\n\n## Campos requeridos\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `client_id` | string | Identificador único del cliente (UNIQUE_ID) |\n| `plate` | string | Matrícula del vehículo |\n\n## Campos opcionales principales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `vin` | string | Número de bastidor (VIN) |\n| `brand_id` | integer | ID de la marca |\n| `model_id` | integer | ID del modelo |\n| `version_id` | integer | ID de la versión |\n| `version_text` | string | Versión (texto libre) |\n| `color` | string | Color exterior |\n| `interior_color` | string | Color interior |\n| `kms` | string | Kilometraje actual |\n| `registration_date` | string | Fecha de matriculación (DD/MM/YYYY) |\n| `model_year` | integer | Año del modelo |\n\n## Campos opcionales técnicos\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `fuel_type_id` | integer | ID del tipo de combustible |\n| `cv` | string | Potencia en CV |\n| `kw` | string | Potencia en kW |\n| `displacement` | string | Cilindrada |\n| `cylinders` | integer | Número de cilindros |\n| `engine_number` | string | Número de motor |\n| `engine_type` | string | Tipo de motor |\n| `oil_type` | string | Tipo de aceite |\n| `ktype` | string | Código KType (TecDoc) |\n| `environmental_label` | integer | Etiqueta medioambiental (0-4) |\n\n## Campos opcionales de mantenimiento\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `next_itv_date` | string | Próxima fecha ITV (DD/MM/YYYY) |\n| `next_revision_date` | string | Próxima fecha revisión (DD/MM/YYYY) |\n| `next_revision_km` | integer | Próximos km para revisión |\n\n## Campos opcionales adicionales\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `insurance_id` | integer | ID de la aseguradora |\n| `policy_number` | string | Número de póliza |\n| `is_fleet` | boolean | Vehículo de flota |\n| `observations` | string | Observaciones |\n\n## Campos auto-generados\n\n- `id` — Identificador único del vehículo (UNIQUE_ID)\n- Asociación al taller del token de autenticación\n\n## Ejemplo de petición\n\n```json\n{\n  \"client_id\": \"7pser1d252xvpoob35lky6eo36peq9xm\",\n  \"plate\": \"1234ABC\",\n  \"vin\": \"WVWZZZ3CZWE123456\",\n  \"brand_id\": 342,\n  \"model_id\": 1081890,\n  \"color\": \"Negro\",\n  \"kms\": \"50000\",\n  \"registration_date\": \"15/03/2022\",\n  \"fuel_type_id\": 2,\n  \"next_itv_date\": \"15/03/2026\"\n}","tags":["Clientes"],"responses":{"200":{"description":"Respuesta exitosa"}},"x-endpoint-id":"cmkw8e2w8000fqub118gyt28n","x-order":12,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewVehicle"},"example":{"client_id":"7pser1d252xvpoob35lky6eo36peq9xm","plate":"1234ABC","vin":"WVWZZZ3CZWE123456","brand_id":342,"model_id":1081890,"color":"Negro","kms":"50000","registration_date":"15/03/2022","next_itv_date":"15/03/2026","fuel_type_id":2}}}},"security":[{"Bearer":[]}]}},"/vehicles/{vehicle_id}":{"get":{"summary":"Get the details of a vehicle","description":"Returns complete information about a vehicle by its unique identifier.\n\n### Route parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `vehicle_id` | string | Unique vehicle identifier (UNIQUE_ID) |\n\n## Data returned\n\n### Basic information\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | string | Unique identifier |\n| `plate` | string | Registration |\n| `vin` | string | Frame (VIN) |\n| `brand` | string | Brand |\n| `model` | string | Model |\n| `client_id` | string | Associated Client ID |\n\n### Technical information\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `kms` | string | Mileage |\n| `registration_date` | string | Registration date |\n| `fuel_type` | string | Fuel type |","operationId":"getVehicleById","tags":["Clientes"],"parameters":[{"name":"vehicle_id","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"brand":{"type":"string"},"model":{"type":"string"},"client_id":{"type":"string"}}}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}},"x-endpoint-id":"ep_vehicle_get_001","x-order":11},"put":{"summary":"Actualiza un vehículo existente","description":"Actualiza los datos de un vehículo existente.\n\n## Validaciones\n\n- **Matrícula única**: No puede existir otro vehículo con la misma matrícula en el taller\n- **Bastidor único**: No puede existir otro vehículo con el mismo bastidor en el taller\n- **Cliente válido**: Si se proporciona `client_id`, debe existir en el sistema\n\n## Campos actualizables\n\n| Campo | Tipo | Descripción |\n|-------|------|-------------|\n| `client_id` | string | ID del cliente asociado |\n| `plate` | string | Matrícula del vehículo |\n| `vin` | string | Número de bastidor (VIN) |\n| `brand_id` | integer | ID de la marca |\n| `model_id` | integer | ID del modelo |\n| `color` | string | Color exterior |\n| `kms` | string | Kilometraje actual |\n| `registration_date` | string | Fecha de matriculación (DD/MM/YYYY) |\n| `fuel_type_id` | integer | ID del tipo de combustible |\n| `next_itv_date` | string | Próxima fecha ITV (DD/MM/YYYY) |\n\n## Notas\n\n- Solo se actualizan los campos enviados en el body\n- La comparación de matrícula/bastidor se hace normalizada","operationId":"updateVehicle","tags":["Clientes"],"parameters":[{"name":"vehicle_id","in":"path","required":true,"description":"","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"plate":{"type":"string"}}}}}},"400":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}},"x-endpoint-id":"ep_vehicle_put_001","x-order":13,"requestBody":{"required":false,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewVehicle"},"example":{"plate":"5678XYZ","color":"Blanco","kms":"75000","next_itv_date":"20/06/2027"}}}}}},"/dgt-lookup/{plate}":{"get":{"summary":"Consulta oficial del vehiculo (DGT)","description":"Obtiene la informacion oficial del vehiculo consultando la DGT.\n\n⚠️ Esta operacion puede tener un coste por consulta.","operationId":"dgtLookup","tags":["Clientes"],"parameters":[{"name":"plate","in":"path","required":true,"description":"Matricula del vehiculo (España).","schema":{"type":"string"}}],"responses":{"200":{"description":"Informacion del vehiculo obtenida con exito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DgtLookupResponse"}}}},"400":{"description":"Matricula no valida.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"codigo":{"type":"string"},"mensaje":{"type":"string"}}},"example":{"ok":false,"codigo":"MATRICULA_INVALIDA","mensaje":"Matricula no valida"}}}},"401":{"description":"Token no valido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}},"402":{"description":"El taller no tiene consultas disponibles.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"codigo":{"type":"string"},"mensaje":{"type":"string"}}},"example":{"ok":false,"codigo":"SIN_CONSULTAS","mensaje":"El taller no tiene consultas disponibles"}}}},"404":{"description":"No se ha encontrado el vehiculo.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"codigo":{"type":"string"},"mensaje":{"type":"string"}}},"example":{"ok":false,"codigo":"VEHICULO_NO_ENCONTRADO","mensaje":"No se han encontrado vehiculos para la matricula"}}}},"502":{"description":"Servicio no disponible.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"codigo":{"type":"string"},"mensaje":{"type":"string"}}},"example":{"ok":false,"codigo":"ERROR_PROVEEDOR","mensaje":"Servicio no disponible"}}}}},"x-endpoint-id":"ep_dgt_lookup","x-order":14,"security":[{"Bearer":[]}]}},"/budgets":{"get":{"summary":"Listado de presupuestos","description":"Obtiene un listado paginado de presupuestos","tags":["Presupuestos"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer","default":10}},{"name":"client_id","in":"query","required":false,"description":"Identificador único de cliente","schema":{"type":"string"}},{"name":"vehicle_id","in":"query","required":false,"description":"Idenfitificador único de vehículo","schema":{"type":"string"}},{"name":"budget_number","in":"query","required":false,"description":"Número de presupuesto","schema":{"type":"string"}},{"name":"from_date","in":"query","required":false,"description":"Fecha desde (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"to_date","in":"query","required":false,"description":"Fecha hasta (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"deleted","in":"query","required":false,"description":"Incluir presupuestos eliminados (por defecto false).","schema":{"type":"boolean","default":false}},{"name":"plate","in":"query","required":false,"description":"Matrícula","schema":{"type":"string"}},{"name":"vin","in":"query","required":false,"description":"Nª Bastidor","schema":{"type":"string"}},{"name":"make","in":"query","required":false,"description":"Marca de vehículo","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de presupuestos","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetListResponse"}}}}},"x-endpoint-id":"cminveqsj00d0zvne29qt051g","x-order":15,"security":[{"Bearer":[]}]},"post":{"summary":"Crear presupuesto","description":"Crea la cabecera de un presupuesto. Solo es obligatorio `client_id` (el identificador que devuelve el listado de clientes); `vehicle_id` e `insurer_id` son opcionales. El identificador y el número se generan automáticamente (el número sigue la serie del taller), el IVA y la divisa se toman de la configuración del taller, y el presupuesto se crea En Elaboración con pagador cliente por defecto. Si no se envía `entry_date` se usa la fecha actual, y `valid_days` fija la validez en días desde la fecha de alta. Las líneas se añaden después con POST /budgets/{budget_id}/lines. Devuelve el presupuesto con la misma estructura que el detalle del GET.","operationId":"createBudget","tags":["Presupuestos"],"responses":{"201":{"description":"Presupuesto creado con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetWriteResponse"}}}},"400":{"description":"Datos inválidos (p. ej. falta client_id o no existe para el taller).","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["client_id is required"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}}},"x-endpoint-id":"ep_budget_post","x-order":19,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetCreateRequest"}}}},"security":[{"Bearer":[]}]}},"/suppliers":{"get":{"summary":"Obtiene un listado de proveedores","description":"Devuelve una lista paginada de proveedores registrados en el sistema.","tags":["Proveedores"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página para la paginación.","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Número de proveedores por página.","schema":{"type":"integer","default":10}},{"name":"supplier_number","in":"query","required":false,"description":"Número de proveedor","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de proveedores obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetSuppliersResponse"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqpw003ozvnepexltkdi","x-order":16,"security":[{"Bearer":[]}]},"post":{"summary":"Crear proveedor","description":"Crea un proveedor. El unico campo obligatorio es `name`. El identificador y el numero de proveedor se generan automaticamente (el numero sigue la serie del taller). Devuelve el proveedor creado.","operationId":"createSupplier","tags":["Proveedores"],"responses":{"201":{"description":"Proveedor creado con exito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierResponse"}}}},"400":{"description":"Datos invalidos (p. ej. falta name).","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["name is required"]}}}},"401":{"description":"Token no valido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}}},"x-endpoint-id":"ep_supplier_post","x-order":20,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierCreateRequest"}}}},"security":[{"Bearer":[]}]}},"/budgets/{budget_id}":{"get":{"summary":"Detalle de una orden de un presupuesto","description":"Obtiene todos los datos relacionados con un presupuesto","tags":["Presupuestos"],"parameters":[{"name":"budget_id","in":"path","required":true,"description":"Identificador único del presupuesto","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalle del presupuesto","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetDetailResponse"}}}}},"x-endpoint-id":"cminveqsx00e8zvnetoba42el","x-order":17,"security":[{"Bearer":[]}]},"put":{"summary":"Actualizar presupuesto","description":"Actualiza la cabecera de un presupuesto existente. Solo se modifican los campos enviados. `status_code` admite 0 (En Elaboración), 1 (Entregado), 2 (Rechazado), 6 (En negociación) y 99 (Caducado); aceptar o facturar se gestiona desde la aplicación. Si el presupuesto está aceptado, firmado, en la papelera o bloqueado devuelve 409 (mismas reglas que las líneas). Devuelve el presupuesto actualizado.","operationId":"updateBudget","tags":["Presupuestos"],"parameters":[{"name":"budget_id","in":"path","required":true,"description":"Identificador único del presupuesto.","schema":{"type":"string"}}],"responses":{"200":{"description":"Presupuesto actualizado con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetWriteResponse"}}}},"400":{"description":"Datos inválidos o sin campos que actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["status_code must be one of 0 (draft), 1 (delivered), 2 (rejected), 6 (negotiating) or 99 (expired)"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}},"404":{"description":"Presupuesto no encontrado.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Budget not found"}}}}},"409":{"description":"El presupuesto no es modificable (aceptado, firmado, en papelera o bloqueado).","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"reason":{"type":"string","description":"accepted | signed | recycled | blocked"}}},"example":{"status":409,"message":"El presupuesto no se puede modificar","reason":"accepted"}}}}},"x-endpoint-id":"ep_budget_put","x-order":21,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetUpdateRequest"}}}},"security":[{"Bearer":[]}]}},"/suppliers/{supplier_id}":{"get":{"summary":"Obtiene el detalle de un proveedor","description":"Devuelve los detalles de un proveedor específico.","tags":["Proveedores"],"parameters":[{"name":"supplier_id","in":"path","required":true,"description":"ID del proveedor a obtener.","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de proveedores obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierDetail"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqq4004gzvneu0putk8l","x-order":18,"security":[{"Bearer":[]}]},"put":{"summary":"Actualizar proveedor","description":"Actualiza los datos de un proveedor existente. Solo se modifican los campos enviados en el cuerpo. Devuelve el proveedor actualizado.","operationId":"updateSupplier","tags":["Proveedores"],"parameters":[{"name":"supplier_id","in":"path","required":true,"description":"Identificador unico del proveedor.","schema":{"type":"string"}}],"responses":{"200":{"description":"Proveedor actualizado con exito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierResponse"}}}},"400":{"description":"Datos invalidos o sin campos que actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["No valid fields provided for update"]}}}},"401":{"description":"Token no valido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}},"404":{"description":"Proveedor no encontrado.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Supplier not found"}}}}}},"x-endpoint-id":"ep_supplier_put","x-order":22,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupplierUpdateRequest"}}}},"security":[{"Bearer":[]}]}},"/budgets/{budget_id}/lines":{"post":{"summary":"Crear linea de presupuesto","description":"Crea una nueva linea dentro de un presupuesto existente. Los campos obligatorios son `line_type` y `description`. Los totales del presupuesto se recalculan automaticamente.\n\n**Restricciones:** No se puede modificar un presupuesto que este aceptado, firmado o en la papelera de reciclaje (error 409).","operationId":"createBudgetLine","tags":["Presupuestos"],"parameters":[{"name":"budget_id","in":"path","required":true,"description":"Identificador unico del presupuesto","schema":{"type":"string"}}],"responses":{"201":{"description":"Linea creada correctamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetLineResponse"}}}},"400":{"description":"Error de validacion: faltan campos requeridos o valores invalidos","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Presupuesto no encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"409":{"description":"El presupuesto no se puede modificar (aceptado, firmado o en papelera)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetModificationError"}}}}},"x-endpoint-id":"ep_budget_line_post","x-order":23,"requestBody":{"required":true,"description":"Datos de la nueva linea de presupuesto. Los campos `line_type` y `description` son obligatorios.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetLineCreate"},"example":{"line_type":1,"description":"Filtro de aceite","reference":"FO-1234","quantity":2,"unit_price":12.5,"discount_percentage":10,"tax_rate":21}}}},"security":[{"Bearer":[]}]}},"/budgets/{budget_id}/lines/{line_id}":{"put":{"summary":"Actualizar linea de presupuesto","description":"Actualiza los campos de una linea de presupuesto existente. Solo se modifican los campos enviados en el body. El campo `line_type` no se puede cambiar. Los totales del presupuesto se recalculan automaticamente.\n\n**Restricciones:** No se puede modificar un presupuesto que este aceptado, firmado o en la papelera de reciclaje (error 409).","operationId":"updateBudgetLine","tags":["Presupuestos"],"parameters":[{"name":"budget_id","in":"path","required":true,"description":"Identificador unico del presupuesto","schema":{"type":"string"}},{"name":"line_id","in":"path","required":true,"description":"Identificador unico de la linea de presupuesto","schema":{"type":"string"}}],"responses":{"200":{"description":"Linea actualizada correctamente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetLineResponse"}}}},"400":{"description":"Error de validacion: no se proporcionaron campos validos para actualizar","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Presupuesto o linea no encontrados","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"409":{"description":"El presupuesto no se puede modificar (aceptado, firmado o en papelera)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetModificationError"}}}}},"x-endpoint-id":"ep_budget_line_put","x-order":24,"requestBody":{"required":true,"description":"Campos a actualizar en la linea. Solo se modifican los campos incluidos. No se permite cambiar `line_type`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetLineUpdate"},"example":{"description":"Filtro de aceite premium","reference":"FO-5678","quantity":3,"unit_price":15,"discount_percentage":5,"tax_rate":21}}}},"security":[{"Bearer":[]}]},"delete":{"summary":"Eliminar linea de presupuesto","description":"Elimina permanentemente una linea de un presupuesto. Los totales del presupuesto se recalculan automaticamente.\n\n**Restricciones:** No se puede modificar un presupuesto que este aceptado, firmado o en la papelera de reciclaje (error 409).","operationId":"deleteBudgetLine","tags":["Presupuestos"],"parameters":[{"name":"budget_id","in":"path","required":true,"description":"Identificador unico del presupuesto","schema":{"type":"string"}},{"name":"line_id","in":"path","required":true,"description":"Identificador unico de la linea de presupuesto","schema":{"type":"string"}}],"responses":{"200":{"description":"Linea eliminada correctamente","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"400":{"description":"Faltan parametros requeridos (budget_id, line_id)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Presupuesto o linea no encontrados","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"409":{"description":"El presupuesto no se puede modificar (aceptado, firmado o en papelera)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetModificationError"}}}}},"x-endpoint-id":"ep_budget_line_delete","x-order":25,"security":[{"Bearer":[]}]}},"/employees":{"get":{"summary":"Obtiene un listado de empleados","description":"Devuelve una lista paginada de empleados registrados en el sistema.","tags":["Empleados"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página para la paginación.","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Número de proveedores por página.","schema":{"type":"integer","default":10}}],"responses":{"200":{"description":"Listado de empleados obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeList"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqq90050zvne3ogkdizs","x-order":26,"security":[{"Bearer":[]}]}},"/repair-orders":{"get":{"summary":"Listado de órdenes de reparación","description":"Obtiene un listado paginado de órdenes de reparación","tags":["Ordenes"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer"}},{"name":"client_id","in":"query","required":false,"description":"Identificador único de cliente","schema":{"type":"string"}},{"name":"vehicle_id","in":"query","required":false,"description":"Idenfitificador único de vehículo","schema":{"type":"string"}},{"name":"order_number","in":"query","required":false,"description":"Número de orden de reparación","schema":{"type":"string"}},{"name":"from_date","in":"query","required":false,"description":"Fecha desde (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"to_date","in":"query","required":false,"description":"Fecha hasta (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"deleted","in":"query","required":false,"description":"Incluir órdenes eliminadas (por defecto false).","schema":{"type":"boolean"}},{"name":"closed","in":"query","required":false,"description":"Filtrar por estado: true para cerradas, false para abiertas.","schema":{"type":"boolean"}},{"name":"plate","in":"query","required":false,"description":"Matrícula","schema":{"type":"string"}},{"name":"vin","in":"query","required":false,"description":"Nº Bastidor","schema":{"type":"string"}},{"name":"make","in":"query","required":false,"description":"Marca vehículo","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de órdenes de reparación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetWorkshopEntriesResponse"}}}}},"x-endpoint-id":"cminveqt200eozvnenyvxn709","x-order":27,"security":[{"Bearer":[]}]},"post":{"summary":"Crear orden de reparación","description":"Crea una orden de reparación. Son obligatorios `client_id` y `vehicle_id` (los identificadores que devuelven los listados de clientes y vehículos); `insurance_company_id` es el identificador del listado de aseguradoras. El identificador y el número de orden se generan automáticamente (el número sigue la serie del taller), el IVA y la divisa se toman de la configuración del taller, y la orden se crea abierta con pagador cliente por defecto. Si no se envía `entry_date`, se usa la fecha actual. Las fechas van en formato DD/MM/YYYY. Los campos de estado (`is_closed`, `service_status_id`, `percentage_completed`, `exit_date`) solo se aceptan en la modificación. Devuelve la orden creada con la misma estructura que el detalle del GET.","operationId":"createRepairOrder","tags":["Ordenes"],"responses":{"201":{"description":"Orden de reparación creada con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairOrderResponse"}}}},"400":{"description":"Datos inválidos (p. ej. falta client_id o vehicle_id, o no existen para el taller).","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["client_id is required","vehicle_id is required"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}}},"x-endpoint-id":"ep_repairorder_post","x-order":31,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairOrderCreateRequest"}}}},"security":[{"Bearer":[]}]}},"/employees/{employee_id}":{"get":{"summary":"Obtiene el detalle de un empleado","description":"Devuelve los detalles de un empleado específico.","tags":["Empleados"],"parameters":[{"name":"employee_id","in":"path","required":true,"description":"ID del empleado a obtener.","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalles del empleado obtenidos con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmployeeDetail"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqqg005ozvnem5671m4d","x-order":28,"security":[{"Bearer":[]}]}},"/repair-orders/{entry_id}":{"get":{"summary":"Detalle de una orden de reparación de taller","description":"Obtiene todos los datos relacionados con una orden específica de taller.","tags":["Ordenes"],"parameters":[{"name":"entry_id","in":"path","required":true,"description":"Identificador único de la entrada de taller","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalle de la entrada de taller","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkshopEntryDetail"}}}}},"x-endpoint-id":"cminveqtf00fwzvnepon5zn8r","x-order":29,"security":[{"Bearer":[]}]},"put":{"summary":"Actualizar orden de reparación","description":"Actualiza una orden de reparación existente. Solo se modifican los campos enviados en el cuerpo. Con `is_closed` se cierra (la fecha de cierre se pone automáticamente) o se reabre la orden; `service_status_id` cambia el estado de servicio y `percentage_completed` el porcentaje completado. Devuelve la orden actualizada.","operationId":"updateRepairOrder","tags":["Ordenes"],"parameters":[{"name":"entry_id","in":"path","required":true,"description":"Identificador único de la orden de reparación.","schema":{"type":"string"}}],"responses":{"200":{"description":"Orden de reparación actualizada con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairOrderResponse"}}}},"400":{"description":"Datos inválidos o sin campos que actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["percentage_completed must be between 0 and 100"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}},"example":{"error":"Token no valido o no autorizado"}}}},"404":{"description":"Orden de reparación no encontrada.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Repair order not found"}}}}}},"x-endpoint-id":"ep_repairorder_put","x-order":33,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairOrderUpdateRequest"}}}},"security":[{"Bearer":[]}]}},"/employees/time-entries":{"get":{"summary":"Consultar fichajes","description":"Consulta los fichajes presenciales de los empleados del taller.\n\n**Sin parametros** devuelve los fichajes de todos los empleados del día actual. Se pueden combinar libremente `employee_id`, `from` y `to`.\n\n**Fechas.** Se admite fecha sola (`2026-08-01`) o fecha y hora. `from` sin hora se toma desde las 00:00:00; `to` sin hora se toma hasta las 00:00:00 del día siguiente, es decir, es un **límite superior exclusivo**. El bloque `period` de la respuesta indica el período que se ha aplicado realmente.\n\n**Turnos nocturnos.** El criterio incluye los fichajes que se solapan con el periodo, de modo que un turno que empieza a las 22:00 y termina a las 06:00 del día siguiente aparece al consultar cualquiera de los dos días.\n\n**Fichajes abiertos.** Un fichaje sin cerrar entra en el resultado siempre que haya empezado antes del fin del período consultado, sin límite por antigüedad. Conviene tenerlo en cuenta: un fichaje que nunca se cerró seguirá apareciendo en todas las consultas posteriores a su inicio.\n\nEl rango máximo por consulta es de 366 días.","operationId":"listTimeEntries","tags":["Empleados"],"parameters":[{"name":"employee_id","in":"query","required":false,"description":"Identificador único del empleado. Si se omite, se devuelven los fichajes de todos los empleados del taller.","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Inicio del período. Fecha (`2026-08-01`) o fecha y hora. Si se omite, el día actual.","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Fin del período, límite exclusivo. Una fecha sin hora se toma como las 00:00 del día siguiente.","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Número de página. Por defecto 1.","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Resultados por página, entre 1 y 100. Por defecto 10.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Fichajes del período consultado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntryList"}}}},"400":{"description":"Parámetros inválidos: formato de fecha incorrecto, to anterior a from o rango mayor de 366 días.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["The requested date range cannot exceed 366 days"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"message":{"type":"string"},"code":{"type":"string"}}},"example":{"error":true,"message":"Invalid or expired API Key.","code":"unauthorized"}}}}},"x-endpoint-id":"ep_time_entries_list","x-order":30,"security":[{"Bearer":[]}]},"post":{"summary":"Añadir fichaje","description":"Crea un fichaje presencial. Son obligatorios `employee_id`, `start_at` y `start_type_id`.\n\n**Fichaje abierto.** Si se omite `end_at`, el fichaje queda abierto, de modo que un dispositivo externo puede registrar primero la entrada y completar la salida después con el endpoint de modificación.\n\n**Fechas.** Se interpretan como hora local del taller: `2026-08-20T08:00:00`. Se admite un indicador de zona horaria (`Z` o `+02:00`), pero **se descarta**: se guarda la fecha y hora tal cual, sin convertir de huso.\n\n**Solapes.** Si el fichaje se solapa con otro del mismo empleado se crea igualmente, pero la respuesta incluye un bloque `warnings` con los fichajes afectados.","operationId":"createTimeEntry","tags":["Empleados"],"responses":{"201":{"description":"Fichaje creado con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"Datos inválidos: faltan campos obligatorios, el empleado o el tipo no existen, el tipo no es del sentido correcto, o las fechas no son coherentes.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["end_at cannot be earlier than start_at"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"message":{"type":"string"},"code":{"type":"string"}}},"example":{"error":true,"message":"Invalid or expired API Key.","code":"unauthorized"}}}}},"x-endpoint-id":"ep_time_entries_post","x-order":34,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntryCreateRequest"}}}},"security":[{"Bearer":[]}]}},"/employees/time-entries/{id}":{"get":{"summary":"Consultar un fichaje","description":"Devuelve un fichaje concreto por su identificador, con la misma estructura que el listado. Un fichaje de otro taller o borrado devuelve 404.","operationId":"getTimeEntry","tags":["Empleados"],"parameters":[{"name":"id","in":"path","required":true,"description":"Identificador del fichaje.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Fichaje encontrado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"message":{"type":"string"},"code":{"type":"string"}}},"example":{"error":true,"message":"Invalid or expired API Key.","code":"unauthorized"}}}},"404":{"description":"Fichaje no encontrado en este taller.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Time entry not found with ID: 352699"}}}}}},"x-endpoint-id":"ep_time_entries_get","x-order":32,"security":[{"Bearer":[]}]},"put":{"summary":"Modificar o corregir fichaje","description":"Corrige un fichaje existente. **Solo hay que enviar los campos que se quieran modificar**; los ausentes no se tocan.\n\nEl caso más habitual es el empleado que olvidó fichar la salida:\n\n```json\n{\"end_at\": \"2026-08-20T14:07:00\", \"end_type_id\": 98331}\n```\n\n**Reabrir un fichaje.** Enviar `end_at` con valor `null` limpia la hora de salida y también el tipo de salida, dejando el fichaje abierto de nuevo. Sirve para deshacer un cierre equivocado.\n\nLa coherencia se comprueba sobre el resultado final, no solo sobre lo enviado: si se envía únicamente `end_at`, se compara con la hora de entrada que ya tiene el fichaje. El empleado de un fichaje no se puede cambiar.\n\nDevuelve el fichaje completo después de aplicar la modificación.","operationId":"updateTimeEntry","tags":["Empleados"],"parameters":[{"name":"id","in":"path","required":true,"description":"Identificador del fichaje que se quiere corregir.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Fichaje corregido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntry"}}}},"400":{"description":"Datos inválidos o sin campos que actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["No valid fields provided for update"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"message":{"type":"string"},"code":{"type":"string"}}},"example":{"error":true,"message":"Invalid or expired API Key.","code":"unauthorized"}}}},"404":{"description":"Fichaje no encontrado en este taller.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Time entry not found with ID: 352699"}}}}}},"x-endpoint-id":"ep_time_entries_put","x-order":35,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntryUpdateRequest"}}}},"security":[{"Bearer":[]}]}},"/invoices":{"get":{"summary":"Listado de facturas","description":"Obtiene un listado paginado de facturas registradas en el sistema. \n\n**Requiere autenticación con token Bearer.**","tags":["Facturas"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer","default":10}},{"name":"client_id","in":"query","required":false,"description":"Identificador único de cliente","schema":{"type":"string"}},{"name":"vehicle_id","in":"query","required":false,"description":"Idenfitificador único de vehículo","schema":{"type":"string"}},{"name":"invoice_number","in":"query","required":false,"description":"Número de factura","schema":{"type":"string"}},{"name":"from_date","in":"query","required":false,"description":"Fecha desde (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"to_date","in":"query","required":false,"description":"Fecha hasta (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"deleted","in":"query","required":false,"description":"Incluir facturas eliminadas (por defecto false).","schema":{"type":"boolean","default":false}},{"name":"plate","in":"query","required":false,"description":"Matrícula","schema":{"type":"string"}},{"name":"vin","in":"query","required":false,"description":"Nº Bastidor","schema":{"type":"string"}},{"name":"make","in":"query","required":false,"description":"Marca vehículo","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de facturas con paginación","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetInvoicesResponse"}}}},"401":{"description":"No autorizado (token inválido o ausente)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqtj00gczvnefu371lmg","x-order":36,"security":[{"Bearer":[]}]}},"/materials":{"get":{"summary":"Obtiene un listado de materiales","description":"Devuelve una lista paginada de materiales almacenados en el sistema.","tags":["Materiales"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página para la paginación.","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Número de materiales por página.","schema":{"type":"integer","default":10}},{"name":"material_ref","in":"query","required":false,"description":"Referencial del material","schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Listado de materiales obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMaterialsResponse"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqql0068zvne83drsc8i","x-order":37,"security":[{"Bearer":[]}]},"post":{"summary":"Crear material","description":"Da de alta un nuevo material. Los campos obligatorios son `reference` y `description`. La `reference` se guarda en mayusculas (sin espacios al inicio/fin) y debe ser unica por taller; si ya existe se devuelve un error 400.\n\nSi se informa `quantity` (stock inicial), ademas de crear el material se genera automaticamente un movimiento de entrada en el almacen.","operationId":"createMaterial","tags":["Materiales"],"responses":{"201":{"description":"Material creado correctamente. Devuelve el material con su stock y movimientos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialDetail"}}}},"400":{"description":"Error de validacion (faltan campos obligatorios) o referencia duplicada.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"ep_material_post","x-order":41,"requestBody":{"required":true,"description":"Datos del nuevo material. Los campos `reference` y `description` son obligatorios. Si se informa `quantity`, se registra como stock inicial.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialCreate"},"example":{"reference":"FILT-1234","description":"Filtro de aceite","cost":3.9,"pvp":10.72,"tax_rate":21,"quantity":5}}}},"security":[{"Bearer":[]}]}},"/invoices/{invoice_id}":{"get":{"summary":"Detalle de una factura","description":"Obtiene el detalle completo de una factura específica, incluyendo las líneas de factura por tipo (repuestos, mano de obra, etc).\n\n### Parámetro requerido:\n- `invoice_id`: ID único de la factura.\n\n**Requiere autenticación con token Bearer.**","tags":["Facturas"],"parameters":[{"name":"invoice_id","in":"path","required":true,"description":"Identificador único de la factura.","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalle completo de la factura incluyendo sus líneas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceComplete"}}}},"401":{"description":"No autorizado (token inválido o ausente)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Factura no encontrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqtx00hozvneybiz3822","x-order":38,"security":[{"Bearer":[]}]}},"/materials/{material_id}":{"get":{"summary":"Obtiene el detalle de un material","description":"Devuelve la información detallada de un material, incluyendo movimientos de stock y fotos.","tags":["Materiales"],"parameters":[{"name":"material_id","in":"path","required":true,"description":"Identificador único del material.","schema":{"type":"string","example":"q9p0zwzfc8csui2xngah3ma1x456yenr"}}],"responses":{"200":{"description":"Detalle del material obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialDetail"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"No se encontró el material con el identificador especificado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqqt0070zvnes9imsp7g","x-order":39,"security":[{"Bearer":[]}]},"put":{"summary":"Modificar material","description":"Actualiza los datos de un material existente. El material se localiza por `material_id` o por su referencia (en el segmento de la ruta). La `reference` no se puede modificar; si se usa para localizar, solo actua como criterio de busqueda.\n\nSi se incluye `quantity`, se calcula la diferencia con el stock actual, se actualiza el stock y se genera el movimiento de almacen correspondiente (entrada o salida).","operationId":"updateMaterial","tags":["Materiales"],"parameters":[{"name":"material_id","in":"path","required":true,"description":"Identificador del material (material_id). Tambien se acepta la referencia del material como valor del segmento.","schema":{"type":"string"}}],"responses":{"200":{"description":"Material actualizado correctamente. Devuelve el material con su stock y movimientos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialDetail"}}}},"400":{"description":"Error de validacion: no se proporcionaron campos validos para actualizar.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Material no encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}},"x-endpoint-id":"ep_material_put","x-order":42,"requestBody":{"required":true,"description":"Campos a actualizar del material. Solo se modifican los campos incluidos. La referencia no se puede modificar. Si se incluye `quantity`, ajusta el stock generando el movimiento de la diferencia.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialUpdate"},"example":{"pvp":12.5,"quantity":7}}}},"security":[{"Bearer":[]}]}},"/materials/{material_id}/movements":{"get":{"summary":"Listado de movimientos de stock de un material","description":"Devuelve una lista paginada de los movimientos de stock asociados a un material.","tags":["Materiales"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página para la paginación.","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Número de movimientos por página.","schema":{"type":"integer","default":10}},{"name":"material_id","in":"path","required":true,"description":"Identificador único del material.","schema":{"type":"string","example":"q9p0zwzfc8csui2xngah3ma1x456yenr"}}],"responses":{"200":{"description":"Listado de movimientos de stock obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMaterialMovementsResponse"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqqz007ozvneazvc2wl4","x-order":40,"security":[{"Bearer":[]}]},"post":{"summary":"Anadir movimiento de stock","description":"Registra un movimiento de stock sobre un material existente. El material se localiza por `material_id` o por su referencia. Se envia el `quantity` como **stock resultante deseado**: se calcula la diferencia con el stock actual, se genera el movimiento de almacen por dicha diferencia y se actualiza el stock acumulado del material.","operationId":"createMaterialMovement","tags":["Materiales"],"parameters":[{"name":"material_id","in":"path","required":true,"description":"Identificador del material (material_id). Tambien se acepta la referencia del material como valor del segmento.","schema":{"type":"string"}}],"responses":{"200":{"description":"Movimiento registrado correctamente. Devuelve el material con su stock actualizado y movimientos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialDetail"}}}},"400":{"description":"Error de validacion: el stock resultante (quantity) es obligatorio y debe ser un entero no negativo.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}},"401":{"description":"No autenticado o token invalido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Material no encontrado","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"}}}}}}},"x-endpoint-id":"ep_material_movement_post","x-order":43,"requestBody":{"required":true,"description":"Stock resultante deseado para el material. Se genera el movimiento de almacen por la diferencia respecto al stock actual.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MaterialStockMovement"},"example":{"quantity":12}}}},"security":[{"Bearer":[]}]}},"/appointments":{"get":{"summary":"Obtiene un listado de citas","description":"Devuelve una lista paginada de citas programadas del taller.\n\n**Búsqueda por matrícula y por teléfono.** Los filtros `plate` y `phone` buscan sobre los datos escritos en la propia cita, no sobre la ficha del cliente, porque una cita puede existir sin que el cliente esté dado de alta. Con cualquiera de los dos, las fechas dejan de hacer falta y se devuelven como máximo las 100 citas más recientes.\n\n**Tipo de cita.** Cada cita incluye `appointment_type_id` y `appointment_type_name`, nulos si no tiene tipo asignado.\n\nLas citas se devuelven ordenadas por fecha, de la más reciente a la más antigua.","tags":["Citas"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página para la paginación.","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Número de citas por página.","schema":{"type":"integer","default":10}},{"name":"client_id","in":"query","required":false,"description":"Identificador único de cliente","schema":{"type":"string"}},{"name":"vehicle_id","in":"query","required":false,"description":"Idenfitificador único de vehículo","schema":{"type":"string"}},{"name":"from_date","in":"query","required":false,"description":"Fecha desde (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"to_date","in":"query","required":false,"description":"Fecha hasta (yyyy-mm-dd).","schema":{"type":"string"}},{"name":"plate","in":"query","required":false,"description":"Matrícula escrita en la cita. Se ignoran mayúsculas, espacios y guiones: `1234-ABC`, `1234 abc` y `1234ABC` son la misma búsqueda.","schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"description":"Teléfono escrito en la cita. Se comparan solo los dígitos y se busca por el final, con un mínimo de 6: `600123456` encuentra `+34 600 12 34 56`. Ojo, no al revés: buscar con prefijo no encuentra los guardados sin él.","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de citas obtenido con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetAppointmentsResponse"}}}},"400":{"description":"Parámetros inválidos. Códigos: `phone_too_short`, `phone_too_long`, `plate_too_long`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"status":400,"error":"phone_too_short","message":"phone must contain at least 6 digits","errors":["phone must contain at least 6 digits"]}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqr7008gzvnezp4nikqz","x-order":44,"security":[{"Bearer":[]}]},"post":{"summary":"Crea una nueva cita","description":"Registra una nueva cita en el sistema.\n\n**Tipo de cita.** `appointment_type_id` es opcional. Si se envía, debe existir en el taller autenticado; si no existe, la cita **no se crea** y se devuelve el código `appointment_type_not_found`. Los valores válidos se obtienen en GET /appointment-types.\n\n**Duración.** `duration` va en horas y es opcional. Si no se envía y el tipo de cita tiene duración configurada, la cita la hereda; si se envía, manda lo que venga en la petición.\n\n**Fechas.** Se admite `DD/MM/YYYY HH:mm` y también ISO 8601 (`2026-10-03T10:30:00`).","tags":["Citas"],"responses":{"201":{"description":"Cita creada con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Appointment"}}}},"400":{"description":"Solicitud incorrecta. Verifique los datos enviados.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"status":400,"error":"appointment_type_not_found","message":"El tipo de cita 7 no existe en este taller"}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqri009kzvneudlei5yd","x-order":46,"requestBody":{"required":true,"description":"Datos de la cita a crear.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAppointmentRequest"}}}},"security":[{"Bearer":[]}]}},"/appointments/times":{"get":{"summary":"Obtiene los tiempos disponibles para una fecha","description":"Devuelve una lista de horarios disponibles para agendar una cita en la fecha especificada.","tags":["Citas"],"parameters":[{"name":"date","in":"query","required":true,"description":"Fecha para la cual se consultan los tiempos disponibles (formato YYYY-MM-DD).","schema":{"type":"string","format":"date","example":"2025-06-18"}}],"responses":{"200":{"description":"Tiempos disponibles obtenidos con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailableTimesResponse"}}}},"400":{"description":"Fecha inválida o formato incorrecto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"401":{"description":"No autorizado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqrv00awzvneixbay0cl","x-order":45,"security":[{"Bearer":[]}]}},"/appointments/{appointment_id}":{"delete":{"summary":"Elimina una cita","description":"Elimina una cita específica del sistema utilizando su ID.","tags":["Citas"],"parameters":[{"name":"appointment_id","in":"path","required":true,"description":"Identificador único de la cita a eliminar.","schema":{"type":"string"}}],"responses":{"204":{"description":"Cita eliminada con éxito. No se devuelve contenido."},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Cita no encontrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqro00a8zvnejj4a2fba","x-order":47,"security":[{"Bearer":[]}]}},"/notifications":{"post":{"summary":"Crear una notificación","description":"Crea una nueva notificación en el sistema.\n\n**Destinatarios.** El campo `users` es opcional: si se omite, la notificación se crea sin destinatarios, igual que antes. Cada usuario debe pertenecer al taller, no estar borrado y tener activada la recepción de notificaciones; los identificadores se obtienen en GET /users.\n\n**Todo o nada.** Si alguno de los usuarios no es válido no se crea nada, ni la notificación ni los destinatarios, y se devuelve el código `user_not_found` con la lista de los rechazados. Los identificadores repetidos se guardan una sola vez y el máximo por petición es 200.\n\n**Respuesta.** Devuelve la notificación creada. Antes devolvía únicamente un mensaje de confirmación.","tags":["Notificaciones"],"responses":{"201":{"description":"Notificación creada con éxito.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"400":{"description":"Solicitud incorrecta. Verifique los datos enviados.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"status":400,"error":"user_not_found","message":"Estos usuarios no existen en este taller o no pueden recibir notificaciones: p8r4tyuj0yy0m11ehx1ndridpq1i6qk8","user_ids":["p8r4tyuj0yy0m11ehx1ndridpq1i6qk8"]}}}},"401":{"description":"No autorizado. El token de acceso es inválido o no fue proporcionado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqs200bkzvne0j3sqimm","x-order":48,"requestBody":{"required":true,"description":"Datos de la notificación a crear.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateNotificationRequest"}}}},"security":[{"Bearer":[]}]}},"/notifications/{id}":{"get":{"summary":"Consultar una notificación","description":"Devuelve una notificación con su lista de destinatarios y si cada uno la ha leído (`seen`).\n\nUna notificación de otro taller devuelve 404.","operationId":"getNotification","tags":["Notificaciones"],"parameters":[{"name":"id","in":"path","required":true,"description":"Identificador único de la notificación.","schema":{"type":"string"}}],"responses":{"200":{"description":"Notificación encontrada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Notification"}}}},"401":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Notificación no encontrada en este taller.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"error":{"type":"integer"},"messages":{"type":"object"}}},"example":{"status":404,"error":404,"messages":{"error":"Notification not found with ID: g2q1..."}}}}}},"x-endpoint-id":"ep_notification_get","x-order":49,"security":[{"Bearer":[]}]}},"/insurers":{"get":{"summary":"Obtiene un listado de aseguradoras","description":"Devuelve una lista paginada de aseguradoras registradas por el taller asociado al **token**","tags":["Aseguradoras"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer","default":1}},{"name":"per_page","in":"query","required":false,"description":"Elementos por página","schema":{"type":"integer","default":10}},{"name":"insurer_number","in":"query","required":false,"description":"Número de la aseguradora","schema":{"type":"string"}}],"responses":{"200":{"description":"Listado de aseguradoras","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetInsurersResponse"}}}},"401":{"description":"No autorizado (token inválido o ausente)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cminveqs900c8zvne4jqf1v8u","x-order":50,"security":[{"Bearer":[]}]}},"/users":{"get":{"summary":"Consultar usuarios","description":"Usuarios del taller. Su utilidad principal es conocer los identificadores que admite el campo `users` al crear una notificación.\n\n**Solo pueden ser destinatarios los usuarios con `receives_notifications` a `true`.** Enviar cualquier otro en `users` devuelve un error `user_not_found`.\n\n","operationId":"listUsers","tags":["Usuarios"],"responses":{"200":{"description":"Usuarios del taller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserList"}}}},"401":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"ep_users_list","x-order":51,"security":[{"Bearer":[]}]}},"/purchase-delivery-notes":{"get":{"summary":"Obtiene albaranes de compra con paginación.","description":"Retorna un listado paginado de albaranes de compra. Soporta paginación con page y per_page.","operationId":"readPurchaseDeliveryNotes","tags":["Albaranes de Compra"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página.","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Listado paginado de albaranes de compra."},"401":{"description":"No autorizado. Token inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cmlhoxm2b001cadxyc8tnfe7n","x-order":52,"security":[{"Bearer":[]}]}},"/purchase-delivery-notes/{id}":{"get":{"summary":"Obtiene un albarán de compra por ID.","description":"Retorna los detalles de un albarán de compra específico.","operationId":"readPurchaseDeliveryNote","tags":["Albaranes de Compra"],"parameters":[{"name":"id","in":"path","required":true,"description":"Identificador del albarán de compra.","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalle del albarán de compra."},"401":{"description":"No autorizado. Token inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Albarán de compra no encontrado."}},"x-endpoint-id":"cmlhowbhm0004adxyhwc6b686","x-order":53,"security":[{"Bearer":[]}]}},"/brands":{"get":{"summary":"Listado de Marcas","description":"Obtiene la lista de todas las marcas de vehículos disponibles.\n\n## Parámetros de consulta opcionales\n\n| Parámetro | Tipo | Descripción |\n|-----------|------|-------------|\n| `search` | string | Filtrar por nombre de la marca |\n| `page` | integer | Número de página (default: 1) |\n| `per_page` | integer | Resultados por página (default: 50, max: 200) |\n\n## Ejemplo de respuesta\n\n```json\n{\n  \"pagination\": {\n    \"current_page\": 1,\n    \"per_page\": 50,\n    \"total_count\": 89,\n    \"total_pages\": 2\n  },\n  \"data\": [\n    {\n      \"id\": 342,\n      \"name\": \"VOLKSWAGEN\"\n    },\n    {\n      \"id\": 265,\n      \"name\": \"SEAT\"\n    },\n    {\n      \"id\": 245,\n      \"name\": \"RENAULT\"\n    }\n  ]\n}\n```","tags":["Marcas y modelos"],"parameters":[{"name":"search","in":"query","required":false,"description":"Nombre de marca","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página","schema":{"type":"integer"}}],"responses":{"200":{"description":"Successful response"}},"x-endpoint-id":"cmiv54sp400vzw4fgpid3p8uw","x-order":54,"requestBody":{"required":true,"description":"","content":{"application/json":{"schema":{},"example":{"client_id":"7pser1d252xvpoob35lky6eo36peq9xm","plate":"1234ABC","vin":"WVWZZZ3CZWE123456","brand_id":342,"model_id":1081890,"color":"Negro","kms":"50000","registration_date":"15/03/2022","next_itv_date":"15/03/2026","fuel_type_id":2}}}},"security":[{"Bearer":[]}]}},"/purchase-invoices":{"get":{"summary":"Obtiene facturas de compra con paginación.","description":"Retorna un listado paginado de facturas de compra. Soporta paginación con page y per_page.","operationId":"readPurchaseInvoices","tags":["Facturas de Compra"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página.","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Listado paginado de facturas de compra."},"401":{"description":"No autorizado. Token inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cmlhoxm5o001yadxy2amwilz9","x-order":55,"security":[{"Bearer":[]}]}},"/brands/{brand_id}/models":{"get":{"summary":"Lista los modelos de una marca específica","description":"Obtiene todos los modelos de vehículos disponibles para una marca específica.\n\n## Parámetros de ruta\n\n| Parámetro | Tipo | Requerido | Descripción |\n|-----------|------|-----------|-------------|\n| `brand_id` | integer | Sí | ID de la marca |\n\n## Parámetros de consulta opcionales\n\n| Parámetro | Tipo | Descripción |\n|-----------|------|-------------|\n| `search` | string | Filtrar por nombre del modelo |\n| `page` | integer | Número de página (default: 1) |\n| `per_page` | integer | Resultados por página (default: 50, max: 200) |\n\n## Ejemplo de respuesta\n\n```json\n{\n  \"pagination\": {\n    \"current_page\": 1,\n    \"per_page\": 50,\n    \"total_count\": 125,\n    \"total_pages\": 3\n  },\n  \"data\": [\n    {\n      \"id\": 1081890,\n      \"brand_id\": 342,\n      \"name\": \"GOLF\",\n      \"vehicle_type_id\": 1\n    }\n  ]\n}","tags":["Marcas y modelos"],"parameters":[{"name":"brand_id","in":"path","required":true,"description":"","schema":{"type":"integer"}},{"name":"search","in":"query","required":false,"description":"Nombre modelo","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Número de página","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página","schema":{"type":"integer"}}],"responses":{"200":{"description":"Respuesta exitosa"}},"x-endpoint-id":"cmkw8fz5y000rqub1iviu23ko","x-order":56,"security":[{"Bearer":[]}]}},"/purchase-invoices/{id}":{"get":{"summary":"Obtiene una factura de compra por ID.","description":"Retorna los detalles de una factura de compra específica.","operationId":"readPurchaseInvoice","tags":["Facturas de Compra"],"parameters":[{"name":"id","in":"path","required":true,"description":"Identificador de la factura de compra.","schema":{"type":"string"}}],"responses":{"200":{"description":"Detalle de la factura de compra."},"401":{"description":"No autorizado. Token inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}},"404":{"description":"Factura de compra no encontrada."}},"x-endpoint-id":"cmlhowbly000qadxy65x9ubqk","x-order":57,"security":[{"Bearer":[]}]}},"/time-entry-types":{"get":{"summary":"Consultar tipos de fichaje","description":"Tabla maestra con los tipos de fichaje configurados en el taller, los mismos que se usan en TallerGP. De aquí se obtienen los valores válidos de `start_type_id` y `end_type_id`.\n\nCada tipo tiene un sentido: `entry` para las entradas y `exit` para las salidas. En las salidas, `counts_as_break` indica si ese periodo se considera una parada o interrupción.\n\nEl identificador de un tipo **solo es único dentro del taller**, no entre talleres, y no tiene por qué ser un número pequeño. Solo se devuelven los tipos activos.","operationId":"listTimeEntryTypes","tags":["Tipos de fichaje"],"parameters":[{"name":"type","in":"query","required":false,"description":"Filtra por sentido: `entry` para tipos de entrada, `exit` para tipos de salida.","schema":{"type":"string","enum":["entry","exit"]}}],"responses":{"200":{"description":"Tipos de fichaje del taller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeEntryTypeList"}}}},"400":{"description":"El parámetro type no es entry ni exit.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"integer"},"message":{"type":"string"},"errors":{"type":"array","items":{"type":"string"}}}},"example":{"status":400,"message":"Validation failed","errors":["type must be either entry or exit"]}}}},"401":{"description":"Token no válido o no autorizado.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"boolean"},"message":{"type":"string"},"code":{"type":"string"}}},"example":{"error":true,"message":"Invalid or expired API Key.","code":"unauthorized"}}}}},"x-endpoint-id":"ep_time_entry_types","x-order":58,"security":[{"Bearer":[]}]}},"/tyres":{"get":{"summary":"Obtiene listado de neumáticos con paginación.","description":"Retorna un listado paginado de neumáticos. Soporta paginación con page y per_page.","operationId":"readTyres","tags":["Neumáticos"],"parameters":[{"name":"page","in":"query","required":false,"description":"Número de página.","schema":{"type":"integer"}},{"name":"per_page","in":"query","required":false,"description":"Número de elementos por página.","schema":{"type":"integer"}}],"responses":{"200":{"description":"Listado paginado de neumáticos."},"401":{"description":"No autorizado. Token inválido o ausente.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"cmlhoxm94002kadxybciddts4","x-order":59,"security":[{"Bearer":[]}]}},"/appointment-types":{"get":{"summary":"Consultar tipos de cita","description":"Tipos de cita configurados en el taller, los mismos que se usan en TallerGP. De aquí se obtienen los valores válidos de `appointment_type_id` al crear una cita.\n\nEl identificador de un tipo **solo es único dentro del taller**, no entre talleres, y no tiene por qué ser un número pequeño.\n\n`duration` se devuelve en horas y suele venir vacía: la mayoría de los tipos no la tienen configurada. Cuando sí la tiene, una cita creada con ese tipo y sin `duration` propia la hereda.\n\nSolo se devuelven los tipos activos, ordenados por su orden de presentación y después por nombre. Los que no tienen orden van al final.","operationId":"listAppointmentTypes","tags":["Tipos de cita"],"responses":{"200":{"description":"Tipos de cita del taller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentTypeList"}}}},"401":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponseFailure"}}}}},"x-endpoint-id":"ep_appointment_types","x-order":60,"security":[{"Bearer":[]}]}}},"components":{"securitySchemes":{"Bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"OauthKey":{"type":"apiKey","in":"header","name":"Oauth-Key"}},"schemas":{"EmployeeList":{"type":"object","description":"Resumen de un empleado en la lista.","properties":{"id":{"type":"string","description":"Identificador unico del empleado."},"employee_number":{"type":"string","description":"Numero de empleado."},"name":{"type":"string","description":"Nombre del empleado."},"surname1":{"type":"string","description":"Primer apellido del empleado."},"surname2":{"type":"string","nullable":true,"description":"Segundo apellido del empleado."}}},"VehicleListItem":{"type":"object","description":"Vehiculo en vista de lista.","properties":{"id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"color":{"type":"string","nullable":true},"kms":{"type":"string","nullable":true},"branch":{"type":"string","description":"Marca."},"model":{"type":"string","nullable":true},"next_itv":{"type":"string","nullable":true},"client_id":{"type":"string"}}},"GetCustomerVehiclesResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/VehicleListItem"}}}},"CustomerVehicleDetail":{"type":"object","description":"Detalle de vehiculo de un cliente.","properties":{"id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"color":{"type":"string","nullable":true},"kms":{"type":"string","nullable":true},"branch":{"type":"string"},"model":{"type":"string","nullable":true},"reg_date":{"type":"string","nullable":true},"version":{"type":"string","nullable":true},"model_year":{"type":"string","nullable":true},"kw":{"type":"string","nullable":true},"cv":{"type":"string","nullable":true},"num_engine":{"type":"string","nullable":true},"displacement":{"type":"string","nullable":true},"next_itv":{"type":"string","nullable":true},"next_services":{"type":"string"},"past_services":{"type":"string"},"documents":{"type":"string"},"client_id":{"type":"string"}}},"CustomerVehicleListItem":{"type":"object","description":"Vehiculo en lista de vehiculos de un cliente (sin client_id).","properties":{"id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"color":{"type":"string","nullable":true},"kms":{"type":"string","nullable":true},"branch":{"type":"string"},"model":{"type":"string","nullable":true},"next_itv":{"type":"string","nullable":true}}},"EmployeeDetail":{"type":"object","description":"Detalle completo de un empleado.","properties":{"id":{"type":"string"},"employee_number":{"type":"string"},"name":{"type":"string"},"surname1":{"type":"string"},"surname2":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"mobile":{"type":"string","nullable":true},"nif":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"postal_code":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"province":{"type":"string","nullable":true},"date_joined":{"type":"string","nullable":true},"date_left":{"type":"string","nullable":true}}},"EmployeeListItem":{"type":"object","properties":{"id":{"type":"string"},"employee_number":{"type":"string"},"name":{"type":"string"},"surname1":{"type":"string"},"surname2":{"type":"string","nullable":true}}},"GetSuppliersResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Supplier"}}}},"Supplier":{"type":"object","description":"Proveedor.","properties":{"id":{"type":"string"},"supplier_number":{"type":"string"},"name":{"type":"string"},"vat_number":{"type":"string","nullable":true},"payment_method":{"type":"string"},"payment_terms":{"type":"string"},"address":{"type":"string","nullable":true},"zip_code":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"province":{"type":"string","nullable":true},"parts_discount":{"type":"number","nullable":true},"labor_discount":{"type":"number","nullable":true},"phone_1":{"type":"string","nullable":true},"phone_2":{"type":"string","nullable":true},"fax":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"account_ledger":{"type":"string","nullable":true},"special_vat":{"type":"number","nullable":true}}},"SupplierDetail":{"type":"object","description":"Detalle de proveedor (mismos campos que lista).","properties":{"id":{"type":"string"},"supplier_number":{"type":"string"},"name":{"type":"string"},"vat_number":{"type":"string","nullable":true},"payment_method":{"type":"string"},"payment_terms":{"type":"string"},"address":{"type":"string","nullable":true},"zip_code":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"province":{"type":"string","nullable":true},"parts_discount":{"type":"number","nullable":true},"labor_discount":{"type":"number","nullable":true},"phone_1":{"type":"string","nullable":true},"phone_2":{"type":"string","nullable":true},"fax":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"account_ledger":{"type":"string","nullable":true},"special_vat":{"type":"number","nullable":true}}},"SupplierContact":{"type":"object","description":"Contacto de proveedor.","properties":{"id":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"position":{"type":"string","nullable":true}}},"GetAppointmentsResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Appointment"}}}},"Notification":{"type":"object","description":"Notificación del taller con sus destinatarios.","properties":{"id":{"type":"string","description":"Identificador único de la notificación.","example":"g2q1plyimmje0ozzbg4f9aug8at6efr6"},"title":{"type":"string","example":"Recordatorio de cita"},"message":{"type":"string","example":"No olvides tu cita para la revisión del vehículo."},"created_at":{"type":"string","description":"Fecha de alta, en formato DD/MM/YYYY HH:mm. La hora es siempre 00:00: la aplicación guarda solo la fecha.","example":"24/09/2026 00:00"},"users":{"type":"array","description":"Destinatarios. Lista vacía si la notificación no tiene ninguno.","items":{"type":"object","properties":{"user_id":{"type":"string","example":"p8rp9nb06ue851ay4wfpr5mjnc25wnd3"},"seen":{"type":"boolean","description":"Si el usuario ya la ha leído.","example":false}}}}},"example":{"id":"g2q1plyimmje0ozzbg4f9aug8at6efr6","title":"Recordatorio de cita","message":"No olvides tu cita para la revisión del vehículo.","created_at":"24/09/2026 00:00","users":[{"user_id":"p8rp9nb06ue851ay4wfpr5mjnc25wnd3","seen":false}]}},"GetInsurersResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Insurer"}}}},"Insurer":{"type":"object","description":"Aseguradora.","properties":{"id":{"type":"string"},"insurer_number":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","nullable":true},"address":{"type":"string","nullable":true},"zip_code":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"province":{"type":"string","nullable":true},"cif":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true},"website":{"type":"string","nullable":true}}},"GetMaterialsResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Material"}}}},"Material":{"type":"object","description":"Material en vista de lista.","properties":{"material_id":{"type":"string"},"reference":{"type":"string","nullable":true},"serial_number":{"type":"string","nullable":true},"name":{"type":"string"},"quantity":{"type":"number"},"cost":{"type":"number"},"pvp":{"type":"number"},"alert_threshold":{"type":"number","nullable":true},"discount1":{"type":"number"},"discount2":{"type":"number"},"margin":{"type":"number"},"tax_rate":{"type":"number"}}},"MaterialDetail":{"type":"object","description":"Detalle completo de un material con movimientos y fotos.","properties":{"material_id":{"type":"string"},"reference":{"type":"string","nullable":true},"serial_number":{"type":"string","nullable":true},"name":{"type":"string"},"quantity":{"type":"number"},"cost":{"type":"number"},"pvp":{"type":"number"},"alert_threshold":{"type":"number","nullable":true},"discount1":{"type":"number"},"discount2":{"type":"number"},"margin":{"type":"number"},"tax_rate":{"type":"number"},"stock_movements":{"type":"array","items":{"$ref":"#/components/schemas/StockMovement"}},"photos":{"type":"array","items":{"$ref":"#/components/schemas/MaterialPhoto"}}}},"StockMovement":{"type":"object","description":"Movimiento de stock de un material.","properties":{"id":{"type":"string"},"movement_date":{"type":"string"},"quantity":{"type":"number"},"entry_id":{"type":"string","nullable":true},"sales_delivery_note_id":{"type":"string","nullable":true},"invoice_id":{"type":"string","nullable":true},"ticket_id":{"type":"string","nullable":true},"purchase_delivery_note_id":{"type":"string","nullable":true},"description":{"type":"string","nullable":true}}},"MaterialPhoto":{"type":"object","description":"Foto de un material.","properties":{"id":{"type":"string"},"unique_code":{"type":"string"},"description":{"type":"string","nullable":true},"document_type_id":{"type":"string","nullable":true},"file_name":{"type":"string"},"width":{"type":"integer","nullable":true},"height":{"type":"integer","nullable":true},"url":{"type":"string"}}},"GetMaterialMovementsResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/StockMovement"}}}},"GetWorkshopEntriesResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/WorkshopEntryListItem"}}}},"WorkshopEntryListItem":{"type":"object","description":"Orden de reparacion en vista de lista.","properties":{"entry_id":{"type":"string"},"order_number":{"type":"string","nullable":true},"entry_date":{"type":"string","nullable":true,"description":"DD/MM/YYYY"},"client_id":{"type":"string","nullable":true},"plate":{"type":"string","nullable":true},"vin":{"type":"string","nullable":true},"vehicle_id":{"type":"string","nullable":true},"total_amount_vat_included":{"type":"number"},"currency":{"type":"string"},"status":{"type":"string","nullable":true},"deleted":{"type":"boolean"},"is_closed":{"type":"boolean"},"service_status_id":{"type":"string","nullable":true},"service_status_name":{"type":"string","nullable":true},"pdf":{"type":"string"}}},"WorkshopEntryDetail":{"type":"object","description":"Detalle completo de una orden de reparacion.","properties":{"entry_id":{"type":"string"},"order_number":{"type":"string"},"is_valued":{"type":"string"},"breakdown_description":{"type":"string","nullable":true},"observations":{"type":"string","nullable":true},"incident_number":{"type":"string","nullable":true},"kilometres":{"type":"string","nullable":true},"is_closed":{"type":"string"},"is_vat_integrated_in_prices":{"type":"string"},"is_not_billable":{"type":"string"},"is_blocked_flag":{"type":"string"},"percentage_completed":{"type":"string","nullable":true},"order_global_discount_percentage":{"type":"string"},"vat_percentage_summary":{"type":"string"},"total_amount_net_from_entry":{"type":"number"},"total_amount_vat_incl_from_entry":{"type":"number"},"entry_date_formatted":{"type":"string"},"entry_datetime_formatted":{"type":"string"},"exit_datetime_formatted":{"type":"string","nullable":true},"delivery_date_formatted":{"type":"string","nullable":true},"delivery_datetime_formatted":{"type":"string","nullable":true},"created_at_datetime_formatted":{"type":"string"},"currency":{"type":"string"},"currency_decimals":{"type":"string"},"client_id":{"type":"string"},"client_full_name":{"type":"string"},"billing_client_id":{"type":"string","nullable":true},"vehicle_id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"service_status_id":{"type":"string","nullable":true},"service_status_name":{"type":"string","nullable":true},"budget_id":{"type":"string","nullable":true},"budget_number":{"type":"string","nullable":true},"associated_invoice_id":{"type":"string"},"associated_invoice_number":{"type":"string"},"parts":{"type":"array","items":{"type":"object"}},"labor":{"type":"array","items":{"type":"object"}},"paint":{"type":"array","items":{"type":"object"}},"other":{"type":"array","items":{"type":"object"}},"wheels":{"type":"array","items":{"type":"object"}},"package_parents":{"type":"string"},"resources":{"type":"object"},"documents":{"type":"array","items":{"type":"object"}},"pdf":{"type":"string"}}},"GetInvoicesResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}}}},"Invoice":{"type":"object","description":"Factura en vista de lista.","properties":{"invoice_id":{"type":"string"},"invoice_number":{"type":"string"},"date":{"type":"string","description":"DD/MM/YYYY"},"payer_info":{"type":"object","properties":{"payer":{"type":"integer"},"payer_id":{"type":"string"}}},"client_id":{"type":"string"},"vehicle_id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"client_name":{"type":"string"},"total_amount_with_vat":{"type":"number"},"total_amount_without_vat":{"type":"number"},"status_name":{"type":"string"},"currency":{"type":"string"},"accounted":{"type":"boolean"},"blocked":{"type":"boolean"},"deleted":{"type":"boolean"},"pdf":{"type":"string"}}},"InvoiceComplete":{"type":"object","description":"Detalle completo de una factura con lineas, recursos y documentos.","properties":{"invoice_id":{"type":"string"},"invoice_number":{"type":"string"},"date":{"type":"string"},"payer_info":{"type":"object"},"client_id":{"type":"string"},"client_name":{"type":"string"},"total_amount_with_vat":{"type":"number"},"total_amount_without_vat":{"type":"number"},"pending_amount":{"type":"number"},"currency":{"type":"string"},"status_name":{"type":"string"},"accounted":{"type":"boolean"},"blocked":{"type":"boolean"},"deleted":{"type":"string"},"billing_client_unique_id":{"type":"string","nullable":true},"vehicle_id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"vehicle_description":{"type":"string"},"subtotal_net_amount":{"type":"string"},"total_tax_amount":{"type":"string"},"tax_rate_summary":{"type":"string"},"payment_terms_name":{"type":"string","nullable":true},"payment_method_name":{"type":"string"},"observations":{"type":"string","nullable":true},"series_name":{"type":"string"},"created_by_user":{"type":"string"},"created_at_formatted":{"type":"string"},"total_parts_amount_with_discount":{"type":"number"},"total_labor_amount_with_discount":{"type":"number"},"total_others_amount_with_discount":{"type":"number"},"total_paint_amount_with_discount":{"type":"number"},"total_tyres_amount_with_discount":{"type":"number"},"global_discount_amount":{"type":"number"},"global_discount_percentage":{"type":"string"},"status_code":{"type":"string"},"status_name_detail":{"type":"string"},"status_color":{"type":"string"},"lines":{"type":"object","properties":{"parts":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"labors":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"others":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"paints":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"tyres":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}}}},"resources":{"type":"array","items":{"type":"object"}},"documents":{"type":"array","items":{"type":"object"}},"pdf":{"type":"string"}}},"InvoiceLine":{"type":"object","description":"Linea de factura.","properties":{"reference":{"type":"string","nullable":true},"description":{"type":"string"},"quantity":{"type":"string"},"unit_price":{"type":"string"},"discount_percentage":{"type":"string"},"tax_rate":{"type":"string"},"total_with_discount":{"type":"string"},"line_type_code":{"type":"string"},"employee_id":{"type":"string","nullable":true},"employee_number":{"type":"string","nullable":true},"work_date":{"type":"string","nullable":true},"is_disbursement":{"type":"boolean"},"visible":{"type":"boolean"}}},"InvoiceLines":{"type":"object","description":"Lineas de factura agrupadas por tipo.","properties":{"parts":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"labors":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"others":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"paints":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}},"tyres":{"type":"array","items":{"$ref":"#/components/schemas/InvoiceLine"}}}},"VehicleDocumentItem":{"type":"object","description":"Documento asociado a un vehiculo.","properties":{"unique_code":{"type":"string"},"document_type":{"type":"string","nullable":true},"file_name":{"type":"string"},"file_size":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"date":{"type":"string","nullable":true}}},"ApiResponseFailure":{"properties":{"reason":{"description":"Error en la petición","example":"Source website could not be found","type":"string"},"success":{"description":"Will be false if the operation failed","example":false,"type":"boolean"}},"type":"object"},"Appointment":{"type":"object","description":"Representa una cita en el sistema.","properties":{"id":{"type":"string","description":"Identificador único de la cita."},"client_id":{"type":"string","nullable":true,"description":"Identificador único del cliente asociado (si existe)."},"vehicle_id":{"type":"string","nullable":true,"description":"Identificador único del vehículo asociado (si existe)."},"date":{"type":"string","description":"Fecha y hora de la cita, en formato DD/MM/YYYY HH:mm.","example":"25/06/2025 13:30"},"name":{"type":"string","description":"Nombre del cliente o de la persona para la cita.","example":"APELLIDO1 APELLIDO2, NOMBRE"},"phone":{"type":"string","nullable":true,"description":"Teléfono de contacto tal como se guardó en la cita.","example":"666666666"},"description":{"type":"string","description":"Descripción o motivo de la cita.","example":"RECARGA GAS AIRE"},"plate":{"type":"string","nullable":true,"description":"Matrícula tal como se guardó en la cita.","example":"0000AAA"},"appointment_type_id":{"type":"integer","nullable":true,"description":"Tipo de cita. Nulo si la cita no tiene tipo asignado.","example":7},"appointment_type_name":{"type":"string","nullable":true,"description":"Descripción del tipo de cita. Nulo si la cita no tiene tipo asignado.","example":"Revisión"}},"example":{"id":"e6kwknqg7q9wasnxqianq9w3fehzy8j2","client_id":"7pser1d252xvpoob35lky6eo36peq9xm","vehicle_id":"9g3rzt5qoezoyvnq4vfa3n39h0tcvhz5","date":"25/06/2025 13:30","name":"APELLIDO1 APELLIDO2, NOMBRE","phone":"666666666","description":"RECARGA GAS AIRE","plate":"0000AAA","appointment_type_id":7,"appointment_type_name":"Revisión"}},"CreateAppointmentRequest":{"type":"object","description":"Datos para crear una nueva cita. La fecha se admite en formato DD/MM/YYYY HH:mm o ISO 8601 (YYYY-MM-DDTHH:MM:SS).","properties":{"client_id":{"type":"string","description":"Identificador único del cliente asociado (opcional).","example":"7pser1d252xvpoob35lky6eo36peq9xm"},"vehicle_id":{"type":"string","description":"Identificador único del vehículo asociado (opcional).","example":"9g3rzt5qoezoyvnq4vfa3n39h0tcvhz5"},"date":{"type":"string","description":"Fecha y hora de la cita. DD/MM/YYYY HH:mm o ISO 8601.","example":"2026-10-03T10:30:00"},"name":{"type":"string","description":"Nombre del cliente o de la persona para la cita.","example":"Laura Gómez"},"phone":{"type":"string","description":"Teléfono de contacto.","example":"600123456"},"description":{"type":"string","description":"Descripción o motivo de la cita.","example":"Revisión anual"},"plate":{"type":"string","description":"Matrícula del vehículo.","example":"1234ABC"},"appointment_type_id":{"type":"integer","description":"Tipo de cita (opcional). Debe existir en el taller autenticado; los valores válidos se obtienen en GET /appointment-types. Si no existe, la cita no se crea.","example":7},"duration":{"type":"number","format":"float","description":"Duración de la cita en horas (opcional). Si no se envía y el tipo de cita tiene duración configurada, la cita la hereda.","example":1.5},"add_note":{"type":"boolean","description":"Indica si se debe añadir una nota adicional (opcional).","example":true},"add_schedule":{"type":"boolean","description":"Si es true, crea además una entrada en la agenda del taller asociada a la cita. Por defecto false.","example":true},"employee_id":{"type":"string","description":"Identificador único del empleado asignado al bloque de agenda (opcional). Solo aplica si add_schedule=true. Si el empleado no existe en el taller, la entrada se crea sin asignación.","example":"lm2dvv24vvfo6k08wxpnikehrhs3tkww"},"estimated_hours":{"type":"number","format":"float","description":"Duración estimada del bloque de agenda en horas (por defecto 1). Solo aplica si add_schedule=true.","example":2}},"required":["date","name","phone","description","plate"],"example":{"date":"2026-10-03T10:30:00","name":"Laura Gómez","phone":"600123456","plate":"1234ABC","description":"Revisión anual","appointment_type_id":7}},"CreateNotificationRequest":{"type":"object","description":"Datos necesarios para crear una nueva notificación.","properties":{"title":{"type":"string","description":"Título de la notificación.","example":"Recordatorio de cita"},"message":{"type":"string","description":"Contenido de la notificación.","example":"No olvides tu cita para la revisión del vehículo."},"users":{"type":"array","description":"Usuarios del taller que recibirán la notificación (opcional). Si se omite o llega vacía, la notificación se crea sin destinatarios. Los identificadores se obtienen en GET /users. Se admite también una lista de cadenas.","maxItems":200,"items":{"type":"object","properties":{"user_id":{"type":"string","description":"Identificador único del usuario.","example":"p8rp9nb06ue851ay4wfpr5mjnc25wnd3"}}}}},"required":["title","message"],"example":{"title":"Recordatorio de cita","message":"No olvides tu cita para la revisión del vehículo.","users":[{"user_id":"p8rp9nb06ue851ay4wfpr5mjnc25wnd3"}]}},"AvailableTimesDetails":{"type":"object","description":"Detalle de los tiempos disponibles para una fecha.","properties":{"date":{"type":"string","format":"date","description":"La fecha para la cual se muestran los tiempos.","example":"2025-06-18"},"description":{"type":"string","description":"Descripción general.","example":"Horas disponibles"},"title":{"type":"string","description":"Título para la sección de tiempos.","example":"Horas"},"is_holiday":{"type":"boolean","description":"Indica si la fecha es un día festivo.","example":false},"times":{"type":"array","items":{"type":"string","format":"time","example":"08:30"},"description":"Lista de horarios disponibles en formato HH:mm."}}},"AvailableTimesResponse":{"type":"object","properties":{"status":{"type":"boolean","example":true},"msg":{"type":"string","example":"Tiempos disponibles para 2025-06-18"},"response":{"$ref":"#/components/schemas/AvailableTimesDetails"}},"example":{"status":true,"msg":"Tiempos disponibles para 2025-06-18","response":{"date":"2025-06-18","description":"Horas disponibles","title":"Horas","is_holiday":false,"times":["08:30","09:30","10:30","11:30","12:30","13:30","14:30","15:30","16:30","17:30","18:30"]}}},"BudgetDetailResponse":{"type":"object","description":"Detalle completo de un presupuesto.","properties":{"budget_id":{"type":"string","description":"Identificador único del presupuesto.","example":"XXXXX"},"budget_number":{"type":"string","description":"Número del presupuesto.","example":"PRE-2024-001"},"budget_date_formatted":{"type":"string","description":"Fecha de creación del presupuesto (formato DD/MM/YYYY).","example":"15/07/2024"},"valid_until_date_formatted":{"type":"string","description":"Fecha de validez del presupuesto (formato DD/MM/YYYY).","example":"14/08/2024"},"status_description":{"type":"string","description":"Descripción del estado del presupuesto (e.g., Pendiente, Aceptado, Rechazado).","example":"Pendiente"},"observations":{"type":"string","description":"Observaciones o notas adicionales del presupuesto.","example":"Presupuesto para revisión anual."},"subtotal_net_amount":{"type":"string","description":"Subtotal neto antes de impuestos.","example":"1200.00"},"total_discount_amount":{"type":"string","description":"Importe total de descuentos aplicados.","example":"50.00"},"total_tax_amount":{"type":"string","description":"Importe total de los impuestos aplicados.","example":"241.50"},"total_amount_vat_included":{"type":"string","description":"Importe total del presupuesto con IVA incluido.","example":"1391.50"},"currency_symbol":{"type":"string","description":"Símbolo de la moneda.","example":"€"},"vat_percentage_summary":{"type":"string","description":"Resumen del porcentaje de IVA aplicado.","example":"21%"},"client_id":{"type":"string","description":"Identificador único del cliente."},"client_full_name":{"type":"string","description":"Nombre completo del cliente."},"customer_number":{"type":"string","description":"Número de cliente."},"client_tax_id":{"type":"string","description":"NIF/CIF del cliente."},"client_address1":{"type":"string","description":"Dirección principal del cliente."},"client_zip_code":{"type":"string","description":"Código postal del cliente."},"client_city":{"type":"string","description":"Ciudad del cliente."},"client_email":{"type":"string","format":"email","description":"Email del cliente."},"client_phone":{"type":"string","description":"Teléfono del cliente."},"client_mobile_phone":{"type":"string","description":"Teléfono móvil del cliente."},"vehicle_id":{"type":"string","description":"Identificador único del vehículo."},"vehicle_plate_number":{"type":"string","description":"Matrícula del vehículo."},"vehicle_vin":{"type":"string","description":"Número de bastidor (VIN) del vehículo."},"vehicle_make_model_description":{"type":"string","description":"Descripción de marca y modelo del vehículo."},"vehicle_kilometres":{"type":"string","description":"Kilometraje del vehículo en el momento del presupuesto."},"budget_lines":{"$ref":"#/components/schemas/BudgetLines","description":"Detalle de las líneas del presupuesto (repuestos, mano de obra, otros)."},"created_by_user_name":{"type":"string","description":"Nombre del usuario que creó el presupuesto."},"created_at_datetime_formatted":{"type":"string","description":"Fecha y hora de creación del presupuesto (formato legible).","example":"15/07/2024 10:30"},"updated_at_datetime_formatted":{"type":"string","description":"Fecha y hora de la última modificación (formato legible).","example":"15/07/2024 11:00"}}},"BudgetLine":{"type":"object","description":"Representa una línea de un presupuesto.","properties":{"line_id":{"type":"string","description":"Identificador único de la línea."},"reference":{"type":"string","example":"REF001","description":"Referencia del artículo/servicio."},"description":{"type":"string","example":"Cambio de aceite y filtro","description":"Descripción detallada."},"quantity":{"type":"string","example":"1","description":"Cantidad."},"unit_price_net":{"type":"string","example":"50","description":"Precio unitario neto."},"discount_percentage":{"type":"string","example":"0","description":"Porcentaje de descuento."},"tax_rate":{"type":"string","example":"21","description":"Tipo de IVA aplicado."},"total_line_amount_net_with_discount":{"type":"string","example":"50","description":"Importe total neto de la línea con descuento."},"line_type_description":{"type":"string","example":"Mano de Obra","description":"Descripción del tipo de línea (Pieza, Mano de Obra, Otros)."}}},"BudgetLines":{"type":"object","description":"Agrupación de líneas de presupuesto por tipo.","properties":{"parts":{"type":"array","items":{"$ref":"#/components/schemas/BudgetLine"},"description":"Líneas de repuestos."},"labors":{"type":"array","items":{"$ref":"#/components/schemas/BudgetLine"},"description":"Líneas de mano de obra."},"others":{"type":"array","items":{"$ref":"#/components/schemas/BudgetLine"},"description":"Otras líneas."}}},"BudgetListItem":{"type":"object","description":"Representa un elemento de la lista de presupuestos.","properties":{"budget_id":{"type":"string","description":"Identificador único del presupuesto.","example":"bgt_123xyz"},"budget_number":{"type":"string","description":"Número del presupuesto.","example":"PRE-2024-001"},"date":{"type":"string","description":"Fecha del presupuesto (formato DD/MM/YYYY).","example":"15/07/2024"},"client_name":{"type":"string","description":"Nombre del cliente.","example":"Cliente Ejemplo S.L."},"vehicle_plate":{"type":"string","description":"Matrícula del vehículo.","example":"1234-ABC"},"total_amount":{"type":"string","description":"Importe total del presupuesto.","example":"1500,50"},"currency_symbol":{"type":"string","description":"Símbolo de la moneda.","example":"€"},"status":{"type":"string","description":"Estado del presupuesto (e.g., Pendiente, Aceptado, Rechazado).","example":"Pendiente"}},"required":["budget_id","budget_number","date","client_name","total_amount","status"]},"BudgetListResponse":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/BudgetListItem"}}}},"CustomerEmbeddedDocument":{"type":"object","description":"Representa un documento embebido en la información del cliente.","properties":{"document_type":{"type":"string","description":"Tipo de documento.","example":"1"},"file_name":{"type":"string","description":"Nombre del archivo.","example":"ampliacion APP.pdf"},"file_size":{"type":"string","description":"Tamaño del archivo en bytes.","example":"211011"},"description":{"type":"string","description":"Descripción del documento.","example":"observaciones pdf"},"title":{"type":"string","description":"Título del documento.","example":"descripcion pdf"},"date":{"type":"string","description":"Fecha del documento (DD/MM/YY).","example":"13/06/25"},"url":{"type":"string","format":"uri","description":"URL del documento.","example":"https://d3lfz47touix8b.cloudfront.net/XXX/clientes/XXXX.pdf"}},"example":{"document_type":"1","file_name":"ampliacion APP.pdf","file_size":"211011","description":"observaciones pdf","title":"descripcion pdf","date":"13/06/25","url":"https://d3lfz47touix8b.cloudfront.net/1004/clientes/XXXXXXXXXXXXX.pdf"}},"ClientContact":{"type":"object","description":"Representa un contacto asociado a un cliente.","properties":{"name":{"type":"string","description":"Nombre del contacto.","example":"CONTACTO 1"},"position":{"type":"string","description":"Cargo del contacto.","example":"jefe"},"phone":{"type":"string","description":"Teléfono del contacto.","example":"666888777"},"schedule":{"type":"string","description":"Horario del contacto.","example":"19:00"},"email":{"type":"string","format":"email","description":"Email del contacto.","example":"email@contacto.com"},"fax":{"type":"string","description":"Fax del contacto.","example":"999666555"}},"example":{"name":"CONTACTO 1","position":"jefe","phone":"666888777","schedule":"19:00","email":"email@contacto.com","fax":"999666555"}},"CustomerNotFound":{"properties":{"status":{"description":"codigo error","type":"number"},"message":{"description":"Customer not found","type":"string"}},"type":"object"},"OAuthTokenRequest":{"properties":{"client_id":{"example":"XXXXXXXXXXXXX","type":"string"},"client_secret":{"example":"XXXXXXXXXXXXX"},"grant_type":{"example":"client_credentials","type":"string"},"scope":{"example":"restapi","type":"string"}},"required":["client_id","client_secret","grant_type","scope"]},"OAuthTokenResponse":{"properties":{"access_token":{"example":"XXXXXXXXXXXXX","type":"string"},"refresh_token":{"example":"XXXXXXXXXXXXX","type":"string"},"token_type":{"example":"Bearer","type":"string"},"expires_at":{"example":1735137750,"type":"integer"},"scope":{"example":"restapi","type":"string"}}},"Pagination":{"properties":{"current_page":{"type":"integer","example":1,"description":"Número de página actual"},"per_page":{"type":"integer","example":10,"description":"Elementos por página"},"total_count":{"type":"integer","example":31,"description":"Nº total de elementos sin paginar"},"total_pages":{"type":"integer","example":4,"description":"Nº total de páginas teniendo en cuenta el numero de elementos"}}},"CustomerListItem":{"type":"object","description":"Representa un cliente en un listado.","properties":{"id":{"type":"string","description":"Identificador único del cliente."},"customer_number":{"type":"string","description":"Número de cliente."},"name":{"type":"string","description":"Nombre del cliente."},"lastname":{"type":"string","description":"Primer apellido del cliente."},"surname":{"type":"string","description":"Segundo apellido del cliente."},"client_type":{"type":"string","description":"Tipo de cliente (e.g., '1' para particular, '2' para empresa)."},"vat_number":{"type":"string","description":"Número de Identificación Fiscal (NIF/CIF) del cliente."},"address":{"type":"string","description":"Dirección del cliente."},"zip_code":{"type":"string","description":"Código postal."},"location":{"type":"string","description":"Localidad."},"province":{"type":"string","description":"Provincia."},"country_num":{"type":"string","description":"Código de país."},"phone":{"type":"string","description":"Teléfono fijo."},"mobile":{"type":"string","description":"Teléfono móvil."},"fax":{"type":"string","description":"Fax."},"mail":{"type":"string","format":"email","description":"Correo electrónico."},"web":{"type":"string","format":"uri","description":"Página web."},"birthdate":{"type":"string","description":"Fecha de nacimiento (DD/MM/YY o vacía)."},"blocked":{"type":"string","description":"Indica si el cliente está bloqueado ('0' no bloqueado, '1' bloqueado)."},"account_ledger":{"type":"string","description":"Cuenta contable."}},"example":{"id":"XXXXXXXXXXXXX","customer_number":"0000000001","name":"Cliente 0000000001","lastname":"","surname":"","client_type":"1","vat_number":"","address":"","zip_code":"006","location":"MALAGA","province":"","country_num":"","phone":"","mobile":"","fax":"","mail":"","web":"","birthdate":"","blocked":"0","account_ledger":""}},"CustomerDetail":{"type":"object","description":"Representa el detalle completo de un cliente.","properties":{"id":{"type":"string","description":"Identificador único del cliente."},"customer_number":{"type":"string","description":"Número de cliente."},"name":{"type":"string","description":"Nombre del cliente."},"lastname":{"type":"string","description":"Primer apellido del cliente."},"surname":{"type":"string","description":"Segundo apellido del cliente."},"client_type":{"type":"string","description":"Tipo de cliente."},"vat_number":{"type":"string","description":"Número de Identificación Fiscal (NIF/CIF)."},"address":{"type":"string","description":"Dirección del cliente."},"zip_code":{"type":"string","description":"Código postal."},"location":{"type":"string","description":"Localidad."},"province":{"type":"string","description":"Provincia."},"country_num":{"type":"string","description":"Código de país."},"phone":{"type":"string","description":"Teléfono fijo."},"mobile":{"type":"string","description":"Teléfono móvil."},"fax":{"type":"string","description":"Fax."},"mail":{"type":"string","format":"email","description":"Correo electrónico."},"web":{"type":"string","format":"uri","description":"Página web."},"birthdate":{"type":"string","description":"Fecha de nacimiento (DD/MM/YY o vacía)."},"blocked":{"type":"string","description":"Indica si el cliente está bloqueado ('0' no bloqueado, '1' bloqueado)."},"account_ledger":{"type":"string","description":"Cuenta contable."},"promos_disabled":{"type":"string","description":"Promociones deshabilitadas ('0' habilitado, '1' deshabilitado)."},"repairs_enabled":{"type":"string","description":"Reparaciones habilitadas ('0' deshabilitado, '1' habilitado)."},"appointments_enabled":{"type":"string","description":"Citas habilitadas ('0' deshabilitado, '1' habilitado)."},"push_disabled":{"type":"string","description":"Notificaciones push deshabilitadas ('0' habilitado, '1' deshabilitado)."},"payment_type":{"type":"string","description":"Tipo de pago preferido por el cliente (si aplica)."},"applied_fee":{"type":"string","description":"Tarifa aplicada."},"app_installed":{"type":"string","description":"Estado de instalación de la app (e.g., 'both')."},"app_installed_date":{"type":"string","description":"Fecha de instalación de la app (DD/MM/YY)."},"documents":{"type":"array","items":{"$ref":"#/components/schemas/CustomerEmbeddedDocument"},"description":"Lista de documentos asociados al cliente."},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/ClientContact"},"description":"Lista de contactos del cliente."}},"example":{"id":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","customer_number":"0000001041","name":"NOMBRE","lastname":"APELLIDO1","surname":"APELLIDO2","client_type":"1","vat_number":"12345678Z","address":"Ramón Casas 30º","zip_code":"02008","location":"ALBACETE","province":"ALBACETE","country_num":"","phone":"666666666","mobile":"666555666","fax":"","mail":"mail@host.com","web":"","birthdate":"","blocked":"0","account_ledger":"222333223","promos_disabled":"1","repairs_enabled":"0","appointments_enabled":"0","push_disabled":"0","payment_type":"","applied_fee":"1","app_installed":"both","app_installed_date":"17/06/25","documents":[{"document_type":"1","file_name":"ampliacion APP.pdf","file_size":"211011","description":"observaciones pdf","title":"descripcion pdf","date":"13/06/25","url":"https://d3lfz47touix8b.cloudfront.net/1004/clientes/XXXXXXXXXXXXX.pdf"}],"contacts":[{"name":"CONTACTO 1","position":"jefe","phone":"666888777","schedule":"19:00","email":"email@contacto.com","fax":"999666555"}]}},"GetClientesListResponse":{"type":"object","description":"Respuesta paginada para la lista de clientes.","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomerListItem"}}}},"NewCustomer":{"type":"object","properties":{"name":{"type":"string","description":"Nombre del cliente","example":"Juan"},"lastname":{"type":"string","description":"Primer apellido","example":"Pérez"},"surname":{"type":"string","description":"Segundo apellido","example":"García"},"customer_number":{"type":"string","description":"Número de cliente único","example":"CLI001"},"vat_number":{"type":"string","description":"NIF/CIF del cliente","example":"12345678A"},"phone":{"type":"string","description":"Teléfono fijo","example":"961234567"},"mobile":{"type":"string","description":"Teléfono móvil","example":"612345678"},"mail":{"type":"string","description":"Correo electrónico","example":"juan@example.com"},"address":{"type":"string","description":"Dirección postal","example":"Calle Mayor 1"},"zip_code":{"type":"string","description":"Código postal","example":"46001"},"location":{"type":"string","description":"Población","example":"Valencia"},"province":{"type":"string","description":"Provincia","example":"Valencia"},"alias":{"type":"string","description":"Alias o nombre comercial"},"observations":{"type":"string","description":"Observaciones"},"parts_discount":{"type":"number","description":"Descuento en piezas (%)","example":10},"labor_discount":{"type":"number","description":"Descuento en mano de obra (%)","example":5},"general_discount":{"type":"number","description":"Descuento general (%)","example":0},"blocked":{"type":"boolean","description":"Cliente bloqueado","example":false}},"required":["name"]},"NewVehicle":{"type":"object","properties":{"client_id":{"type":"string","description":"ID del cliente propietario","example":"7pser1d252xvpoob35lky6eo36peq9xm"},"plate":{"type":"string","description":"Matrícula del vehículo","example":"1234ABC"},"vin":{"type":"string","description":"Número de bastidor (VIN)","example":"WVWZZZ3CZWE123456"},"brand_id":{"type":"integer","description":"ID de la marca","example":342},"model_id":{"type":"integer","description":"ID del modelo","example":1081890},"color":{"type":"string","description":"Color del vehículo","example":"Negro"},"kms":{"type":"string","description":"Kilometraje actual","example":"50000"},"registration_date":{"type":"string","description":"Fecha de matriculación (DD/MM/YYYY)","example":"15/03/2022"},"fuel_type_id":{"type":"integer","description":"ID del tipo de combustible","example":2},"next_itv_date":{"type":"string","description":"Próxima fecha ITV (DD/MM/YYYY)","example":"15/03/2026"}},"required":["plate"]},"Vehicle":{"type":"object","description":"Detalle completo de un vehiculo.","properties":{"id":{"type":"string","description":"Identificador unico del vehiculo."},"plate":{"type":"string","description":"Matricula del vehiculo."},"vin":{"type":"string","description":"Numero de bastidor (VIN)."},"color":{"type":"string","nullable":true,"description":"Color del vehiculo."},"reg_date":{"type":"string","nullable":true,"description":"Fecha de matriculacion (DD/MM/YYYY)."},"kms":{"type":"string","nullable":true,"description":"Kilometraje actual."},"branch":{"type":"string","description":"Marca del vehiculo."},"model":{"type":"string","nullable":true,"description":"Modelo del vehiculo."},"version":{"type":"string","nullable":true,"description":"Version del vehiculo."},"model_year":{"type":"string","nullable":true,"description":"Ano del modelo."},"kw":{"type":"string","nullable":true,"description":"Potencia en kilovatios."},"cv":{"type":"string","nullable":true,"description":"Potencia en caballos de vapor."},"num_engine":{"type":"string","nullable":true,"description":"Numero de motor."},"displacement":{"type":"string","nullable":true,"description":"Cilindrada en cc."},"next_itv":{"type":"string","nullable":true,"description":"Fecha de proxima ITV."},"next_services":{"type":"string","description":"Proximas revisiones programadas."},"past_services":{"type":"string","description":"Revisiones anteriores."},"documents":{"type":"string","description":"Documentos asociados."},"client_id":{"type":"string","description":"ID del cliente propietario."}},"required":["id","plate"]},"IntakeDetailResponse":{"type":"object","description":"Detalle completo de un resguardo (entrada de vehículo).","properties":{"id":{"type":"string","description":"Identificador único del resguardo."},"intake_number":{"type":"string","description":"Número de resguardo."},"entry_date":{"type":"string","description":"Fecha de entrada (DD/MM/YYYY)."},"client_id":{"type":"string","description":"Identificador único del cliente."},"vehicle_id":{"type":"string","description":"Identificador único del vehículo."},"plate":{"type":"string","description":"Matrícula del vehículo."},"km":{"type":"string","description":"Kilometraje del vehículo."},"status_code":{"type":"integer","description":"Código de estado: 1=Abierto, 2=Cerrado."},"status_name":{"type":"string","description":"Nombre legible del estado."},"status_color":{"type":"string","description":"Color hex asociado al estado."},"depositor_name":{"type":"string","nullable":true,"description":"Nombre del depositante."},"estimated_date":{"type":"string","nullable":true,"description":"Fecha estimada de finalización (DD/MM/YYYY)."},"is_blocked":{"type":"boolean","description":"Indica si el resguardo está bloqueado."},"is_archived":{"type":"boolean","description":"Indica si el resguardo está archivado."},"observations":{"type":"string","description":"Observaciones visibles del resguardo."},"internal_observations":{"type":"string","description":"Observaciones internas (no visibles al cliente)."},"acceptance_code":{"type":"string","nullable":true,"description":"Código de aceptación."},"siniester_number":{"type":"string","nullable":true,"description":"Número de siniestro asociado."},"insurance_amount":{"type":"number","description":"Importe del seguro.","example":0},"next_itv_date":{"type":"string","nullable":true,"description":"Fecha de próxima ITV (DD/MM/YYYY)."},"send_date":{"type":"string","nullable":true,"description":"Fecha de envío."},"has_parts_reception":{"type":"boolean","description":"Indica si tiene recepción de piezas."},"important_notice":{"type":"boolean","description":"Indica si tiene aviso importante."},"employee_name":{"type":"string","description":"Nombre del empleado responsable."},"fuel_level_code":{"type":"integer","description":"Código del nivel de combustible."},"fuel_level_name":{"type":"string","description":"Descripción del nivel de combustible.","example":"1/2 deposito"},"insurer_id":{"type":"string","nullable":true,"description":"Identificador único de la aseguradora."},"bill_to_client_id":{"type":"string","nullable":true,"description":"Identificador del cliente al que se factura."},"billing_group_name":{"type":"string","description":"Nombre del grupo de facturación."}}},"IntakeListItem":{"type":"object","description":"Resumen de un resguardo (entrada de vehículo) en el listado.","properties":{"id":{"type":"string","description":"Identificador único del resguardo.","example":"es6b4l40ic7sfk3pqw0sfay6y39bt9w0"},"intake_number":{"type":"string","description":"Número de resguardo.","example":"0000000025"},"entry_date":{"type":"string","description":"Fecha de entrada (DD/MM/YYYY).","example":"20/02/2026"},"client_id":{"type":"string","description":"Identificador único del cliente."},"vehicle_id":{"type":"string","description":"Identificador único del vehículo."},"plate":{"type":"string","description":"Matrícula del vehículo.","example":"2964-KBP"},"km":{"type":"string","description":"Kilometraje del vehículo en el momento de la entrada.","example":"70000"},"status_code":{"type":"integer","description":"Código de estado del resguardo: 1=Abierto, 2=Cerrado.","example":1},"status_name":{"type":"string","description":"Nombre legible del estado.","example":"Abierto"},"status_color":{"type":"string","description":"Color hex asociado al estado.","example":"#3cb371"},"depositor_name":{"type":"string","nullable":true,"description":"Nombre del depositante."},"estimated_date":{"type":"string","nullable":true,"description":"Fecha estimada de finalización (DD/MM/YYYY)."},"is_blocked":{"type":"boolean","description":"Indica si el resguardo está bloqueado."},"is_archived":{"type":"boolean","description":"Indica si el resguardo está archivado."}}},"IntakeListResponse":{"type":"object","description":"Respuesta paginada del listado de resguardos.","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"data":{"type":"array","items":{"$ref":"#/components/schemas/IntakeListItem"}}}},"ApiError":{"type":"object","description":"Error de validación o de regla de negocio. El campo error es un código estable: conviene programar contra él y no contra el texto de message, que puede cambiar.","properties":{"status":{"type":"integer","example":400},"error":{"type":"string","description":"Código del error.","example":"appointment_type_not_found"},"message":{"type":"string","description":"Mensaje legible.","example":"El tipo de cita 7 no existe en este taller"},"errors":{"type":"array","description":"Solo cuando hay varios mensajes de validación.","items":{"type":"string"}},"user_ids":{"type":"array","description":"Solo en user_not_found: identificadores rechazados.","items":{"type":"string"}}}},"AppointmentTypeList":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Identificador del tipo. Único dentro del taller, no entre talleres."},"name":{"type":"string","description":"Descripción configurada en el taller."},"color":{"type":"string","nullable":true,"description":"Color en hexadecimal, con almohadilla."},"duration":{"type":"number","format":"float","nullable":true,"description":"Duración en horas. Nula si no está informada; la mayoría de los tipos no la tienen."},"order":{"type":"integer","nullable":true,"description":"Orden de presentación. Los tipos sin orden se devuelven al final."}}}}}},"BudgetCreateRequest":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string","description":"Identificador del cliente (obligatorio)"},"vehicle_id":{"type":"string","description":"Identificador del vehiculo (opcional)"},"insurer_id":{"type":"string","description":"Identificador de la aseguradora"},"entry_date":{"type":"string","description":"Fecha de alta DD/MM/YYYY (por defecto, hoy)"},"valid_days":{"type":"integer","description":"Dias de validez del presupuesto (calcula la fecha de validez desde la fecha de alta)"},"kilometers":{"type":"integer","description":"Kilometros del vehiculo"},"observations":{"type":"string","description":"Observaciones"},"incident_number":{"type":"string","description":"Numero de siniestro"},"payer_type_id":{"type":"integer","description":"Pagador: 1=cliente (por defecto), 2=aseguradora, 3=leasing, 4=otro cliente"}}},"BudgetLineCreate":{"type":"object","required":["line_type","description"],"properties":{"line_type":{"type":"integer","description":"Tipo de linea: 1=piezas, 2=mano de obra, 3=pintura, 4=subcontrata, 5=otros","enum":[1,2,3,4,5]},"description":{"type":"string","description":"Descripcion de la linea"},"reference":{"type":"string","description":"Referencia del articulo o servicio"},"quantity":{"type":"number","description":"Cantidad (default: 1)","default":1},"unit_price":{"type":"number","description":"Precio unitario (default: 0)","default":0},"discount_percentage":{"type":"number","description":"Porcentaje de descuento (default: 0)","default":0},"tax_rate":{"type":"number","description":"Porcentaje de IVA. Si no se indica, hereda el del presupuesto"}}},"BudgetLineResponse":{"type":"object","properties":{"line_id":{"type":"string","description":"Identificador unico de la linea"},"description":{"type":"string","description":"Descripcion de la linea"},"reference":{"type":"string","description":"Referencia del articulo o servicio"},"quantity":{"type":"number","description":"Cantidad"},"unit_price":{"type":"number","description":"Precio unitario"},"discount_percentage":{"type":"number","description":"Porcentaje de descuento"},"tax_rate":{"type":"number","description":"Porcentaje de IVA"},"line_type":{"type":"integer","description":"Tipo de linea (1-5)"},"total_with_discount":{"type":"number","description":"Total de la linea con descuento aplicado"}}},"BudgetLineUpdate":{"type":"object","properties":{"description":{"type":"string","description":"Descripcion de la linea"},"reference":{"type":"string","description":"Referencia del articulo o servicio"},"quantity":{"type":"number","description":"Cantidad"},"unit_price":{"type":"number","description":"Precio unitario"},"discount_percentage":{"type":"number","description":"Porcentaje de descuento"},"tax_rate":{"type":"number","description":"Porcentaje de IVA"}}},"BudgetModificationError":{"type":"object","properties":{"status":{"type":"integer","description":"Codigo HTTP"},"message":{"type":"string","description":"Mensaje de error descriptivo"},"reason":{"type":"string","description":"Razon del bloqueo: accepted, signed o recycled","enum":["accepted","signed","recycled"]}}},"BudgetUpdateRequest":{"type":"object","properties":{"client_id":{"type":"string"},"vehicle_id":{"type":"string"},"insurer_id":{"type":"string"},"entry_date":{"type":"string","description":"DD/MM/YYYY"},"valid_days":{"type":"integer"},"kilometers":{"type":"integer"},"observations":{"type":"string"},"incident_number":{"type":"string"},"payer_type_id":{"type":"integer","description":"1=cliente, 2=aseguradora, 3=leasing, 4=otro cliente"},"status_code":{"type":"integer","description":"Estado: 0=En Elaboracion, 1=Entregado, 2=Rechazado, 6=En negociacion, 99=Caducado. Aceptar y Facturar se gestionan desde la aplicacion"}}},"BudgetWriteResponse":{"type":"object","description":"Misma estructura que el detalle de GET /budgets/{budget_id}: cabecera, cliente, vehiculo, totales, lineas por tipo (parts, labors, others, paints, tyres), recursos y documentos.","properties":{"budget_id":{"type":"string"},"budget_number":{"type":"string"},"client_id":{"type":"string"},"vat_percentage":{"type":"string"},"created_at":{"type":"string"},"vat_included":{"type":"string"},"status_id":{"type":"string"},"status_name":{"type":"string"},"client_full_name":{"type":"string"},"currency":{"type":"string"},"total_with_vat":{"type":"number","nullable":true},"total_without_vat":{"type":"number","nullable":true},"client_number":{"type":"string"},"valid_days":{"type":"string","nullable":true},"deleted":{"type":"boolean"},"vehicle_id":{"type":"string","nullable":true},"plate":{"type":"string","nullable":true},"vin":{"type":"string","nullable":true},"brand":{"type":"string","nullable":true},"model":{"type":"string","nullable":true},"lines":{"type":"object"},"resources":{"type":"array"},"documents":{"type":"array"},"pdf":{"type":"string"}}},"DgtLookupResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"matricula":{"type":"string","description":"Matricula normalizada"},"bastidor":{"type":"string","description":"Bastidor (VIN) del vehiculo"},"consultasDisponibles":{"type":"integer","description":"Saldo de consultas del taller tras descontar"},"fechaConsulta":{"type":"string","description":"Fecha del dato (DD/MM/YYYY)"},"datos":{"type":"object","description":"Informacion tecnica oficial del vehiculo"}}},"IntakeCreateRequest":{"type":"object","required":["client_id","vehicle_id"],"properties":{"client_id":{"type":"string","description":"Identificador del cliente (obligatorio)"},"vehicle_id":{"type":"string","description":"Identificador del vehiculo (obligatorio)"},"insurer_id":{"type":"string","description":"Identificador de la aseguradora"},"entry_date":{"type":"string","description":"Fecha de entrada DD/MM/YYYY (por defecto, hoy)"},"estimated_date":{"type":"string","description":"Fecha prevista DD/MM/YYYY"},"send_date":{"type":"string","description":"Fecha de envio DD/MM/YYYY"},"km":{"type":"string","description":"Kilometros del vehiculo"},"depositor_name":{"type":"string","description":"Nombre del depositante"},"observations":{"type":"string","description":"Observaciones"},"internal_observations":{"type":"string","description":"Observaciones internas"},"acceptance_code":{"type":"integer","description":"Codigo de aceptacion"},"siniester_number":{"type":"string","description":"Numero de siniestro"},"insurance_amount":{"type":"number","description":"Importe del seguro"},"has_parts_reception":{"type":"boolean","description":"Recepcion de piezas"},"important_notice":{"type":"boolean","description":"Aviso importante"},"fuel_level_code":{"type":"integer","description":"Nivel de combustible: 0=lleno, 1=3/4, 2=1/2, 3=1/4, 4=reserva"}}},"IntakeResponse":{"type":"object","properties":{"id":{"type":"string"},"intake_number":{"type":"string"},"entry_date":{"type":"string"},"client_id":{"type":"string"},"vehicle_id":{"type":"string"},"plate":{"type":"string"},"km":{"type":"string"},"status_code":{"type":"integer"},"status_name":{"type":"string"},"status_color":{"type":"string"},"depositor_name":{"type":"string"},"estimated_date":{"type":"string"},"is_blocked":{"type":"boolean"},"is_archived":{"type":"boolean"},"observations":{"type":"string"},"internal_observations":{"type":"string","nullable":true},"acceptance_code":{"type":"integer","nullable":true},"siniester_number":{"type":"string","nullable":true},"insurance_amount":{"type":"number"},"next_itv_date":{"type":"string","nullable":true},"send_date":{"type":"string","nullable":true},"has_parts_reception":{"type":"boolean"},"important_notice":{"type":"boolean"},"employee_name":{"type":"string","nullable":true},"fuel_level_code":{"type":"integer","nullable":true},"fuel_level_name":{"type":"string","nullable":true},"insurer_id":{"type":"string","nullable":true},"bill_to_client_id":{"type":"string","nullable":true},"billing_group_name":{"type":"string","nullable":true}}},"IntakeUpdateRequest":{"type":"object","properties":{"client_id":{"type":"string"},"vehicle_id":{"type":"string"},"insurer_id":{"type":"string"},"entry_date":{"type":"string","description":"DD/MM/YYYY"},"estimated_date":{"type":"string","description":"DD/MM/YYYY"},"send_date":{"type":"string","description":"DD/MM/YYYY"},"km":{"type":"string"},"depositor_name":{"type":"string"},"observations":{"type":"string"},"internal_observations":{"type":"string"},"acceptance_code":{"type":"integer"},"siniester_number":{"type":"string"},"insurance_amount":{"type":"number"},"has_parts_reception":{"type":"boolean"},"important_notice":{"type":"boolean"},"fuel_level_code":{"type":"integer","description":"0=lleno, 1=3/4, 2=1/2, 3=1/4, 4=reserva"},"status_code":{"type":"integer","description":"1=Abierto, 2=Cerrado"}}},"MaterialCreate":{"type":"object","required":["reference","description"],"properties":{"reference":{"type":"string","description":"Referencia o codigo del material. Se almacena en mayusculas y sin espacios al inicio/fin. Debe ser unica por taller."},"description":{"type":"string","description":"Nombre o descripcion del material (se acepta tambien el alias name)."},"serial_number":{"type":"string","description":"Numero de serie del material"},"quantity":{"type":"integer","description":"Stock inicial. Si se informa (>0) se genera automaticamente un movimiento de entrada en el almacen.","default":0},"cost":{"type":"number","format":"float","description":"Coste unitario"},"pvp":{"type":"number","format":"float","description":"Precio de venta al publico"},"alert_threshold":{"type":"integer","description":"Umbral de alerta de stock minimo"},"discount1":{"type":"number","format":"float","description":"Primer porcentaje de descuento"},"discount2":{"type":"number","format":"float","description":"Segundo porcentaje de descuento"},"margin":{"type":"number","format":"float","description":"Margen de beneficio (porcentaje)"},"tax_rate":{"type":"number","format":"float","description":"Porcentaje de IVA"}}},"MaterialStockMovement":{"type":"object","required":["quantity"],"properties":{"quantity":{"type":"integer","description":"Stock resultante deseado. Se calcula la diferencia con el stock actual y se genera un movimiento de almacen por dicha diferencia."},"reference":{"type":"string","description":"Referencia del material, como localizador alternativo si no se usa el material_id en la ruta."}}},"MaterialUpdate":{"type":"object","properties":{"description":{"type":"string","description":"Nombre o descripcion del material (alias: name)"},"serial_number":{"type":"string","description":"Numero de serie del material"},"quantity":{"type":"integer","description":"Nuevo stock deseado. Se calcula la diferencia con el stock actual y se genera el movimiento correspondiente."},"cost":{"type":"number","format":"float","description":"Coste unitario"},"pvp":{"type":"number","format":"float","description":"Precio de venta al publico"},"alert_threshold":{"type":"integer","description":"Umbral de alerta de stock minimo"},"discount1":{"type":"number","format":"float","description":"Primer porcentaje de descuento"},"discount2":{"type":"number","format":"float","description":"Segundo porcentaje de descuento"},"margin":{"type":"number","format":"float","description":"Margen de beneficio (porcentaje)"},"tax_rate":{"type":"number","format":"float","description":"Porcentaje de IVA"}}},"RepairOrderCreateRequest":{"type":"object","required":["client_id","vehicle_id"],"properties":{"client_id":{"type":"string","description":"Identificador del cliente (obligatorio)"},"vehicle_id":{"type":"string","description":"Identificador del vehiculo (obligatorio)"},"insurance_company_id":{"type":"string","description":"Identificador de la aseguradora"},"entry_date":{"type":"string","description":"Fecha de entrada DD/MM/YYYY (por defecto, hoy)"},"delivery_date":{"type":"string","description":"Fecha de entrega prevista DD/MM/YYYY"},"kilometres":{"type":"string","description":"Kilometros del vehiculo"},"breakdown_description":{"type":"string","description":"Descripcion de la averia"},"observations":{"type":"string","description":"Observaciones"},"incident_number":{"type":"string","description":"Numero de siniestro"},"insurance_deductible_amount":{"type":"number","description":"Franquicia del seguro"},"payer_type_id":{"type":"integer","description":"Pagador: 1=cliente (por defecto), 2=aseguradora, 3=leasing, 4=otro cliente"},"fuel_level_id":{"type":"integer","description":"Nivel de combustible: 0=lleno, 1=3/4, 2=1/2, 3=1/4, 4=reserva"},"collect_replaced_parts":{"type":"boolean","description":"Recoger piezas sustituidas"},"notify_unforeseen_budget":{"type":"boolean","description":"Avisar si surge presupuesto imprevisto"},"next_revision_date":{"type":"string","description":"Proxima revision: fecha DD/MM/YYYY"},"next_revision_km":{"type":"integer","description":"Proxima revision: kilometros"},"next_revision_description":{"type":"string","description":"Proxima revision: descripcion"}}},"RepairOrderResponse":{"type":"object","description":"Misma estructura que el detalle de GET /repair-orders/{entry_id}: datos de la orden, cliente, vehiculo, importes y lineas (parts, labor, paint, other, wheels), documentos y recursos.","properties":{"entry_id":{"type":"string"},"order_number":{"type":"string"},"breakdown_description":{"type":"string"},"observations":{"type":"string"},"kilometres":{"type":"string"},"is_closed":{"type":"string"},"percentage_completed":{"type":"string","nullable":true},"service_status_id":{"type":"string","nullable":true},"vat_percentage_summary":{"type":"string"},"currency":{"type":"string"},"entry_date_formatted":{"type":"string"},"delivery_date_formatted":{"type":"string"},"client_id":{"type":"string"},"client_full_name":{"type":"string"},"vehicle_id":{"type":"string"},"plate":{"type":"string"},"vin":{"type":"string"},"payer_type_id":{"type":"string"},"fuel_level_id":{"type":"string"},"fuel_level_name":{"type":"string"},"insurance_company_id":{"type":"string","nullable":true},"next_revision_km_entry_level":{"type":"string","nullable":true},"parts":{"type":"array","items":{"type":"object"}},"labor":{"type":"array","items":{"type":"object"}},"paint":{"type":"array","items":{"type":"object"}},"other":{"type":"array","items":{"type":"object"}},"wheels":{"type":"array","items":{"type":"object"}},"documents":{"type":"array","items":{"type":"object"}},"pdf":{"type":"string"}}},"RepairOrderUpdateRequest":{"type":"object","properties":{"client_id":{"type":"string"},"vehicle_id":{"type":"string"},"insurance_company_id":{"type":"string"},"entry_date":{"type":"string","description":"DD/MM/YYYY"},"delivery_date":{"type":"string","description":"DD/MM/YYYY"},"exit_date":{"type":"string","description":"Fecha de salida DD/MM/YYYY"},"kilometres":{"type":"string"},"breakdown_description":{"type":"string"},"observations":{"type":"string"},"incident_number":{"type":"string"},"insurance_deductible_amount":{"type":"number"},"payer_type_id":{"type":"integer","description":"1=cliente, 2=aseguradora, 3=leasing, 4=otro cliente"},"fuel_level_id":{"type":"integer","description":"0=lleno, 1=3/4, 2=1/2, 3=1/4, 4=reserva"},"collect_replaced_parts":{"type":"boolean"},"notify_unforeseen_budget":{"type":"boolean"},"next_revision_date":{"type":"string","description":"DD/MM/YYYY"},"next_revision_km":{"type":"integer"},"next_revision_description":{"type":"string"},"is_closed":{"type":"boolean","description":"true cierra la orden (la fecha de cierre se pone automaticamente), false la reabre"},"service_status_id":{"type":"integer","description":"Estado de servicio (catalogo de estados)"},"percentage_completed":{"type":"integer","description":"Porcentaje completado (0-100)"}}},"SupplierCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Nombre del proveedor (obligatorio)"},"vat_number":{"type":"string","description":"CIF/NIF"},"address":{"type":"string","description":"Direccion"},"zip_code":{"type":"string","description":"Codigo postal"},"city":{"type":"string","description":"Poblacion"},"province":{"type":"string","description":"Provincia"},"parts_discount":{"type":"integer","description":"Descuento en piezas (%)"},"labor_discount":{"type":"integer","description":"Descuento en mano de obra (%)"},"phone_1":{"type":"string","description":"Telefono 1"},"phone_2":{"type":"string","description":"Telefono 2"},"fax":{"type":"string"},"email":{"type":"string"},"website":{"type":"string","description":"Pagina web"},"account_ledger":{"type":"string","description":"Cuenta contable"},"special_vat":{"type":"integer","description":"IVA especial"}}},"SupplierResponse":{"type":"object","properties":{"id":{"type":"string"},"supplier_number":{"type":"string"},"name":{"type":"string"},"vat_number":{"type":"string"},"payment_method":{"type":"string","nullable":true},"payment_terms":{"type":"string","nullable":true},"address":{"type":"string"},"zip_code":{"type":"string"},"city":{"type":"string"},"province":{"type":"string"},"parts_discount":{"type":"integer"},"labor_discount":{"type":"integer"},"phone_1":{"type":"string"},"phone_2":{"type":"string"},"fax":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"account_ledger":{"type":"string"},"special_vat":{"type":"integer"},"contacts":{"type":"array","items":{"type":"object"}}}},"SupplierUpdateRequest":{"type":"object","properties":{"name":{"type":"string"},"vat_number":{"type":"string"},"address":{"type":"string"},"zip_code":{"type":"string"},"city":{"type":"string"},"province":{"type":"string"},"parts_discount":{"type":"integer"},"labor_discount":{"type":"integer"},"phone_1":{"type":"string"},"phone_2":{"type":"string"},"fax":{"type":"string"},"email":{"type":"string"},"website":{"type":"string"},"account_ledger":{"type":"string"},"special_vat":{"type":"integer"}}},"TimeEntry":{"type":"object","properties":{"id":{"type":"integer","description":"Identificador del fichaje"},"employee_id":{"type":"string","description":"Identificador único del empleado"},"employee_name":{"type":"string","nullable":true,"description":"Nombre y apellidos del empleado"},"start_at":{"type":"string","description":"Fecha y hora de entrada, hora local del taller, sin desfase horario"},"end_at":{"type":"string","nullable":true,"description":"Fecha y hora de salida. Nulo indica que el fichaje sigue abierto"},"start_type":{"type":"object","nullable":true,"properties":{"id":{"type":"integer"},"description":{"type":"string"}}},"end_type":{"type":"object","nullable":true,"properties":{"id":{"type":"integer"},"description":{"type":"string"}}},"observations":{"type":"string","nullable":true},"warnings":{"type":"array","description":"Solo en alta y modificación, si el fichaje se solapa con otro del mismo empleado","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"time_entry_ids":{"type":"array","items":{"type":"integer"}}}}}}},"TimeEntryCreateRequest":{"type":"object","required":["employee_id","start_at","start_type_id"],"properties":{"employee_id":{"type":"string","description":"Identificador único del empleado (obligatorio)"},"start_at":{"type":"string","description":"Fecha y hora de entrada en hora local del taller. Formato YYYY-MM-DDTHH:MM:SS. Se admite un offset de zona horaria, pero se descarta: se toma la fecha y hora tal cual (obligatorio)"},"start_type_id":{"type":"integer","description":"Tipo de fichaje de entrada, debe ser de sentido entry (obligatorio)"},"end_at":{"type":"string","nullable":true,"description":"Fecha y hora de salida. Si se omite, el fichaje queda abierto"},"end_type_id":{"type":"integer","nullable":true,"description":"Tipo de fichaje de salida, debe ser de sentido exit"},"observations":{"type":"string","nullable":true,"description":"Observaciones, hasta 1500 caracteres"}}},"TimeEntryList":{"type":"object","properties":{"pagination":{"type":"object","properties":{"current_page":{"type":"integer"},"per_page":{"type":"integer"},"total_count":{"type":"integer"},"total_pages":{"type":"integer"}}},"period":{"type":"object","description":"Período realmente aplicado a la consulta","properties":{"from":{"type":"string"},"to":{"type":"string","description":"Límite superior exclusivo"}}},"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeEntry"}}}},"TimeEntryTypeList":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","description":"Identificador del tipo, único dentro del taller"},"type":{"type":"string","enum":["entry","exit"],"description":"Sentido del fichaje"},"description":{"type":"string","description":"Descripción configurada en el taller"},"order":{"type":"integer","nullable":true,"description":"Orden de presentación"},"counts_as_break":{"type":"boolean","description":"Solo en salidas: el período se considera parada"},"automatic_close":{"type":"boolean","description":"El tipo se cierra automáticamente"}}}}}},"TimeEntryUpdateRequest":{"type":"object","description":"Modificación parcial: solo se tocan los campos presentes. Un null explícito en end_at reabre el fichaje y limpia también el tipo de salida.","properties":{"start_at":{"type":"string","description":"Nueva fecha y hora de entrada"},"start_type_id":{"type":"integer","description":"Nuevo tipo de entrada"},"end_at":{"type":"string","nullable":true,"description":"Nueva fecha y hora de salida. Enviar null reabre el fichaje"},"end_type_id":{"type":"integer","nullable":true,"description":"Nuevo tipo de salida"},"observations":{"type":"string","nullable":true}}},"UserList":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Identificador único del usuario. Es el valor que se envía en el campo users al crear una notificación."},"login":{"type":"string","description":"Nombre de acceso."},"name":{"type":"string","nullable":true,"description":"Nombre descriptivo. Puede ser nulo: no todos los usuarios lo tienen."},"receives_notifications":{"type":"boolean","description":"Si el usuario tiene activada la recepción de notificaciones. Solo estos pueden ser destinatarios."},"employee_id":{"type":"string","nullable":true,"description":"Identificador del empleado vinculado, si lo hay."}}}}}}}}}