{
  "openapi": "3.0.3",
  "info": {
    "title": "DECA ERP API",
    "version": "1.8.0",
    "description": "API REST para integrar DECA ERP con sistemas de facturación, expediciones y gestión de flotas. Permite crear viajes incompletos, obtener inmediatamente un enlace privado de cumplimentación, consultar su estado, descargar el PDF vigente, sincronizar maestros, importar clientes por lotes y gestionar repartos con varios envíos.\n\nLa autenticación se envía siempre en la cabecera `X-Api-Key`. Las llamadas de prueba actúan sobre la empresa asociada a esa clave.",
    "contact": {
      "name": "Soporte DECA ERP",
      "email": "nts@netsistemas.com",
      "url": "https://deca.netsistemas.com/integracion-erp.html"
    },
    "license": {
      "name": "Uso sujeto a las condiciones del servicio",
      "url": "https://deca.netsistemas.com/legal.php"
    }
  },
  "externalDocs": {
    "description": "Guía de integración ERP, ejemplos y proyecto demostrativo",
    "url": "https://deca.netsistemas.com/integracion-erp.html"
  },
  "servers": [
    {
      "url": "https://deca.netsistemas.com",
      "description": "Servidor de DECA ERP"
    }
  ],
  "tags": [
    {
      "name": "Escritura",
      "description": "Alta y modificación de documentos DeCA. El campo `accion` del JSON selecciona la operación."
    },
    {
      "name": "Consulta",
      "description": "Consulta individual, búsqueda por referencia del ERP y listados filtrados."
    },
    {
      "name": "Historial",
      "description": "Versiones PDF inmutables y auditoría de cambios de cada documento."
    },
    {
      "name": "Descargas",
      "description": "Preparación asíncrona de lotes ZIP y seguimiento de su estado."
    },
    {
      "name": "Cumplimentación",
      "description": "Enlaces privados para que el transportista complete y finalice los datos autorizados."
    },
    {
      "name": "Repartos",
      "description": "Documentos con varios envíos. Cada envío identifica su origen, destino, referencia y líneas de mercancía."
    },
    {
      "name": "Maestros ERP",
      "description": "Sincronización idempotente de clientes, transportistas, vehículos y conductores mediante `origenRegistro` e `idExterno`."
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "UserApiKeyAuth": []
    }
  ],
  "paths": {
    "/api.php": {
      "post": {
        "tags": [
          "Escritura"
        ],
        "operationId": "escribirDeca",
        "summary": "Crear o actualizar un DeCA",
        "description": "Use `accion=crear` para un alta y `accion=actualizar` junto con `id` para modificar un documento. La actualización funciona como un PATCH: conserva los campos que no se envían. Si se incluye `lineas`, sustituye todas las líneas de mercancía existentes.\n\nUn alta sin `fechaTransporte` queda no planificada y todavía no genera PDF, pero la respuesta ya incluye `urlEdicion`. El permiso `modoEdicionTransportista` se guarda en el servidor: `operativo` autoriza fecha y matrículas; `carga` añade descripción, cantidad, unidad y peso de las mercancías. El transportista puede guardar borradores y finalizar; el ERP consulta `estadoCumplimentacion`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/DecaCreateRequest"
                  },
                  {
                    "$ref": "#/components/schemas/DecaUpdateRequest"
                  }
                ],
                "discriminator": {
                  "propertyName": "accion",
                  "mapping": {
                    "crear": "#/components/schemas/DecaCreateRequest",
                    "actualizar": "#/components/schemas/DecaUpdateRequest"
                  }
                }
              },
              "examples": {
                "crearPlanificado": {
                  "summary": "Crear un viaje con fecha y mercancías",
                  "value": {
                    "accion": "crear",
                    "cargadorNombre": "Harinas Leonesas SL",
                    "cargadorNif": "B24010101",
                    "cargadorDomicilio": "Pol. Ind. León Oeste 12, León",
                    "transportistaNombre": "Transportes del Norte SL",
                    "transportistaNif": "B00000001",
                    "origen": "León",
                    "destino": "Valladolid",
                    "fechaTransporte": "2026-08-20",
                    "matriculaTractora": "1234 KLM",
                    "matriculaRemolque": "R 1234 ABC",
                    "numAlbaran": "ALB-2026-001",
                    "origenRegistro": "ERP_CLIENTE",
                    "idExterno": "EXP-12345",
                    "lineas": [
                      {
                        "descripcion": "Harina de trigo",
                        "cantidad": 40,
                        "unidad": "sacos",
                        "pesoKg": 1000
                      },
                      {
                        "descripcion": "Sémola de trigo",
                        "cantidad": 10,
                        "unidad": "sacos",
                        "pesoKg": 250
                      }
                    ]
                  }
                },
                "crearNoPlanificado": {
                  "summary": "Crear un viaje pendiente de fecha",
                  "value": {
                    "accion": "crear",
                    "cargadorNombre": "Cerámicas Levante SA",
                    "cargadorNif": "A46020202",
                    "origen": "Valencia",
                    "destino": "Burgos",
                    "origenRegistro": "ERP_CLIENTE",
                    "idExterno": "PRE-2026-0042",
                    "modoEdicionTransportista": "carga",
                    "diasValidezEnlace": 30,
                    "observaciones": "Pendiente de planificación"
                  }
                },
                "asignarFecha": {
                  "summary": "Asignar fecha a un viaje no planificado",
                  "value": {
                    "accion": "actualizar",
                    "id": 125,
                    "fechaTransporte": "2026-08-21",
                    "cargadorDomicilio": "Av. Mediterráneo 18, Valencia",
                    "matriculaTractora": "7350 LPD",
                    "lineas": [
                      {
                        "descripcion": "Azulejo cerámico paletizado",
                        "cantidad": 18,
                        "unidad": "palets",
                        "pesoKg": 12600
                      }
                    ]
                  }
                },
                "actualizarVehiculo": {
                  "summary": "Cambiar vehículo sin alterar el resto",
                  "value": {
                    "accion": "actualizar",
                    "id": 125,
                    "matriculaTractora": "7350 LPD",
                    "matriculaRemolque": "R 8841 LHG",
                    "observaciones": "Cambio de tractora comunicado desde el ERP"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Documento creado o actualizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecaWriteResponse"
                },
                "examples": {
                  "conPdf": {
                    "summary": "Viaje con fecha",
                    "value": {
                      "ok": true,
                      "idDeca": 125,
                      "token": "7f4ef35861d34c748be6d12058741b96",
                      "url": "https://deca.netsistemas.com/deca.php?t=7f4ef35861d34c748be6d12058741b96",
                      "numVersion": 1,
                      "pdf": true
                    }
                  },
                  "sinPdf": {
                    "summary": "Viaje pendiente de fecha",
                    "value": {
                      "ok": true,
                      "idDeca": 126,
                      "token": "98d49c58694f4ccf8dd6585726127454",
                      "url": "https://deca.netsistemas.com/deca.php?t=98d49c58694f4ccf8dd6585726127454",
                      "urlDocumento": null,
                      "urlDescargaPdf": null,
                      "urlEdicion": "https://deca.netsistemas.com/completar_matriculas.php?t=ejemplo_privado",
                      "modoEdicionTransportista": "carga",
                      "camposEditables": [
                        "fechaTransporte",
                        "matriculaTractora",
                        "matriculaRemolque",
                        "mercancias"
                      ],
                      "estadoCumplimentacion": "no_iniciado",
                      "enlaceActivo": true,
                      "numVersion": null,
                      "pdf": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "tags": [
          "Consulta"
        ],
        "operationId": "consultarDeca",
        "summary": "Consultar, buscar o listar DeCAs",
        "description": "El parámetro `accion` selecciona la consulta:\n\n- `consultar`: recupera un documento por `id`, incluido el estado de cumplimentación.\n- `enlace_edicion`: devuelve el mismo enlace privado activo o lo crea si aún no existe.\n- `buscar`: localiza el documento enlazado al ERP por `origen` e `idExterno`.\n- `listar`: devuelve una página de resultados y admite fechas opcionales.\n\nPara listar viajes no planificados use `noPlanificados=1`. En ese caso no filtre por fecha de transporte, ya que esos viajes no tienen ese valor.",
        "parameters": [
          {
            "name": "accion",
            "in": "query",
            "required": true,
            "description": "Tipo de consulta que se va a ejecutar.",
            "schema": {
              "type": "string",
              "enum": [
                "consultar",
                "enlace_edicion",
                "buscar",
                "listar"
              ]
            },
            "example": "listar"
          },
          {
            "name": "id",
            "in": "query",
            "description": "Identificador DeCA. Obligatorio cuando `accion=consultar` o `accion=enlace_edicion`.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 125
          },
          {
            "name": "modoEdicionTransportista",
            "in": "query",
            "description": "Permiso del enlace. Solo para `accion=enlace_edicion`; no reabre enlaces ya finalizados.",
            "schema": {
              "type": "string",
              "enum": [
                "operativo",
                "ruta",
                "carga",
                "completo"
              ],
              "default": "operativo"
            }
          },
          {
            "name": "diasValidezEnlace",
            "in": "query",
            "description": "Validez de un enlace nuevo. Solo para `accion=enlace_edicion`.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "Código estable del sistema origen. Obligatorio cuando `accion=buscar`.",
            "schema": {
              "type": "string"
            },
            "example": "ERP_CLIENTE"
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Identificador del envío, expedición o albarán en el ERP. Obligatorio cuando `accion=buscar`.",
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "example": "EXP-12345"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Número máximo de registros. Solo para `accion=listar`.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Primer registro de la página. Solo para `accion=listar`.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "fechaCampo",
            "in": "query",
            "description": "Fecha sobre la que se aplican `fechaDesde` y `fechaHasta`. Solo para `accion=listar`.",
            "schema": {
              "type": "string",
              "enum": [
                "creacion",
                "modificacion",
                "registro",
                "transporte"
              ],
              "default": "creacion"
            }
          },
          {
            "name": "fechaDesde",
            "in": "query",
            "description": "Inicio inclusivo del filtro. Es opcional y puede usarse sin fecha final.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-08-01"
          },
          {
            "name": "fechaHasta",
            "in": "query",
            "description": "Fin inclusivo del filtro. Es opcional y puede usarse sin fecha inicial.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-08-31"
          },
          {
            "name": "noPlanificados",
            "in": "query",
            "description": "Use `1` para devolver únicamente viajes sin `fechaTransporte`. Solo para `accion=listar`.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta. La estructura depende del valor de `accion`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/DecaConsultaResponse"
                    },
                    {
                      "$ref": "#/components/schemas/DecaBusquedaResponse"
                    },
                    {
                      "$ref": "#/components/schemas/DecaListadoResponse"
                    },
                    {
                      "$ref": "#/components/schemas/EnlaceEdicionResponse"
                    }
                  ]
                },
                "examples": {
                  "consulta": {
                    "summary": "Resultado de consultar por id",
                    "value": {
                      "ok": true,
                      "idDeca": 125,
                      "url": "https://deca.netsistemas.com/deca.php?t=7f4ef35861d34c748be6d12058741b96",
                      "numVersion": 2,
                      "fechaTransporte": "2026-08-21",
                      "matriculaTractora": "1234 KLM",
                      "matriculaRemolque": null,
                      "estado": {
                        "anulado": false,
                        "terminado": false,
                        "albaranado": true,
                        "numAlbaran": "ALB-2026-001"
                      },
                      "origenRegistro": "ERP_CLIENTE",
                      "idExterno": "EXP-12345",
                      "lineas": [
                        {
                          "descripcion": "Harina de trigo",
                          "cantidad": 40,
                          "unidad": "sacos",
                          "pesoKg": 1000
                        }
                      ]
                    }
                  },
                  "busquedaNoEncontrada": {
                    "summary": "La referencia del ERP no existe",
                    "value": {
                      "ok": true,
                      "encontrado": false
                    }
                  },
                  "listado": {
                    "summary": "Página de resultados",
                    "value": {
                      "ok": true,
                      "total": 1,
                      "limit": 100,
                      "offset": 0,
                      "fechaCampo": "creacion",
                      "items": [
                        {
                          "idDeca": 125,
                          "fechaTransporte": "2026-08-21",
                          "cargadorNombre": "Harinas Leonesas SL",
                          "origen": "León",
                          "destino": "Valladolid",
                          "mercancia": "Harina de trigo",
                          "numVersion": 2,
                          "url": "https://deca.netsistemas.com/deca.php?t=7f4ef35861d34c748be6d12058741b96",
                          "fechaCreacion": "2026-08-20 09:30",
                          "fechaModificacion": "2026-08-20 10:15",
                          "fechaRegistro": "2026-08-20",
                          "origenRegistro": "ERP_CLIENTE",
                          "idExterno": "EXP-12345",
                          "estado": {
                            "anulado": false,
                            "terminado": false,
                            "albaranado": true,
                            "numAlbaran": "ALB-2026-001"
                          }
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_versiones.php": {
      "get": {
        "tags": [
          "Historial"
        ],
        "operationId": "consultarVersionesDeca",
        "summary": "Consultar el historial o descargar una versión PDF",
        "description": "Sin `version`, devuelve las versiones PDF y el registro de cambios. Con `version`, descarga ese PDF histórico. Con `actual=1`, descarga directamente el PDF vigente. Todas las llamadas requieren la cabecera `X-Api-Key`. Use `incluirDetalle=1` para incluir las instantáneas anterior y posterior de cada cambio.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "Identificador del DeCA.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 125
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "Número de versión que se desea descargar como PDF.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 2
          },
          {
            "name": "actual",
            "in": "query",
            "required": false,
            "description": "Use `1` para descargar directamente la versión PDF vigente.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            }
          },
          {
            "name": "incluirDetalle",
            "in": "query",
            "required": false,
            "description": "Incluye datos anteriores y nuevos en cada movimiento.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Historial JSON o contenido PDF, según los parámetros.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "example": true
                    },
                    "idDeca": {
                      "type": "integer",
                      "example": 125
                    },
                    "numVersionActual": {
                      "type": "integer",
                      "nullable": true,
                      "example": 3
                    },
                    "versiones": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "numVersion": {
                            "type": "integer"
                          },
                          "actual": {
                            "type": "boolean"
                          },
                          "fechaCreacion": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "tamanoBytes": {
                            "type": "integer"
                          },
                          "urlDescarga": {
                            "type": "string",
                            "format": "uri"
                          }
                        }
                      }
                    },
                    "cambios": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "idAuditoria": {
                            "type": "integer"
                          },
                          "accion": {
                            "type": "string",
                            "enum": [
                              "ALTA",
                              "MODIFICACION",
                              "FINALIZACION"
                            ]
                          },
                          "origen": {
                            "type": "string",
                            "enum": [
                              "WEB",
                              "API",
                              "ENLACE"
                            ]
                          },
                          "actor": {
                            "type": "string",
                            "nullable": true
                          },
                          "campos": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "numVersion": {
                            "type": "integer",
                            "nullable": true
                          },
                          "fecha": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "numeroEmpresa": {
                      "type": "integer",
                      "format": "int64",
                      "minimum": 1,
                      "readOnly": true,
                      "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
                    }
                  }
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api_repartos.php": {
      "post": {
        "tags": [
          "Repartos"
        ],
        "operationId": "guardarReparto",
        "summary": "Crear o actualizar un DeCA con varios envíos",
        "description": "Use `accion=crear` para el alta y `accion=actualizar` junto con `id` para una modificación parcial. Si se incluye `envios`, la colección completa anterior queda sustituida. Sin `fechaTransporte` el documento queda pendiente y no genera PDF.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accion"
                ],
                "properties": {
                  "accion": {
                    "type": "string",
                    "enum": [
                      "crear",
                      "actualizar"
                    ]
                  },
                  "id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Obligatorio al actualizar."
                  },
                  "idCliente": {
                    "type": "integer",
                    "nullable": true
                  },
                  "idTransportista": {
                    "type": "integer",
                    "nullable": true
                  },
                  "cargadorNombre": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "cargadorNif": {
                    "type": "string",
                    "maxLength": 20
                  },
                  "cargadorDomicilio": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "transportistaNombre": {
                    "type": "string",
                    "maxLength": 150
                  },
                  "transportistaNif": {
                    "type": "string",
                    "maxLength": 20
                  },
                  "fechaTransporte": {
                    "type": "string",
                    "format": "date",
                    "nullable": true
                  },
                  "matriculaTractora": {
                    "type": "string",
                    "maxLength": 15,
                    "nullable": true
                  },
                  "matriculaRemolque": {
                    "type": "string",
                    "maxLength": 15,
                    "nullable": true
                  },
                  "observaciones": {
                    "type": "string",
                    "nullable": true
                  },
                  "origenRegistro": {
                    "type": "string",
                    "maxLength": 50,
                    "nullable": true
                  },
                  "idExterno": {
                    "type": "string",
                    "maxLength": 512,
                    "nullable": true,
                    "description": "Identificador estable del correo, pedido o expedición. Máximo 512 unidades UTF-16; no se recorta. Junto con origenRegistro es único por empresa."
                  },
                  "modoEdicionTransportista": {
                    "type": "string",
                    "enum": [
                      "operativo",
                      "ruta",
                      "carga",
                      "completo"
                    ],
                    "default": "operativo",
                    "description": "`operativo` permite fecha y matrículas; `ruta` añade origen y destino; `carga` añade líneas de mercancía; `completo` permite ruta y mercancía."
                  },
                  "diasValidezEnlace": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 30
                  },
                  "envios": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/EnvioReparto"
                    }
                  }
                }
              },
              "examples": {
                "crearReparto": {
                  "summary": "Ruta con dos entregas",
                  "value": {
                    "accion": "crear",
                    "cargadorNombre": "Distribuciones Centro SL",
                    "cargadorNif": "B28030303",
                    "cargadorDomicilio": "Calle Comercio 15, Madrid",
                    "transportistaNombre": "Transportes del Norte SL",
                    "transportistaNif": "B00000001",
                    "fechaTransporte": "2026-08-24",
                    "matriculaTractora": "1234 KLM",
                    "origenRegistro": "ERP_CLIENTE",
                    "idExterno": "RUTA-2026-0087",
                    "envios": [
                      {
                        "referencia": "PED-4501",
                        "origen": "Madrid",
                        "destino": "Toledo",
                        "lineas": [
                          {
                            "descripcion": "Conservas en cajas",
                            "cantidad": 40,
                            "unidad": "cajas",
                            "pesoKg": 520
                          }
                        ]
                      },
                      {
                        "referencia": "PED-4502",
                        "origen": "Toledo",
                        "destino": "Ciudad Real",
                        "lineas": [
                          {
                            "descripcion": "Bebidas paletizadas",
                            "cantidad": 8,
                            "unidad": "palets",
                            "pesoKg": 4300
                          }
                        ]
                      }
                    ]
                  }
                },
                "actualizarMatricula": {
                  "summary": "Modificar solo los datos comunes",
                  "value": {
                    "accion": "actualizar",
                    "id": 125,
                    "matriculaTractora": "7350 LPD"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reparto actualizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepartoResponse"
                }
              }
            }
          },
          "201": {
            "description": "Reparto creado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepartoResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "tags": [
          "Repartos"
        ],
        "operationId": "consultarRepartos",
        "summary": "Consultar, buscar o listar repartos",
        "parameters": [
          {
            "name": "accion",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "consultar",
                "buscar",
                "listar"
              ]
            }
          },
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "soloRepartos",
            "in": "query",
            "description": "Use 1 para excluir documentos de un único envío.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api_clientes.php": {
      "get": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "consultarEntidades",
        "summary": "Consultar o listar clientes y transportistas",
        "description": "Sin parametros de identificacion devuelve un listado paginado. Para obtener un registro concreto use `id` o la pareja `origen` + `idExterno`.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Identificador interno del entidad.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "Sistema que asigno la referencia externa. Debe enviarse junto a idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Identificador estable del registro en el ERP. Debe enviarse junto a origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filtra por estado. El valor predeterminado devuelve activos e inactivos.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busqueda libre en los campos principales y la referencia externa.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Numero maximo de elementos de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Primer elemento de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "rol",
            "in": "query",
            "description": "Filtra las entidades por su uso en DeCA.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "cliente",
                "transportista",
                "ambos"
              ],
              "default": "todos"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ClienteItemResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ClienteListResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "guardarEntidad",
        "summary": "Crear, actualizar, activar o desactivar una entidad",
        "description": "Use `accion=guardar` para sincronizar de forma idempotente. Si ya existe la pareja `origenRegistro` + `idExterno`, el registro se actualiza; si no existe, se crea. `actualizar`, `activar` y `desactivar` admiten `id` o referencia externa. No se realiza borrado fisico.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClienteWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Crear o actualizar entidad desde el ERP",
                  "value": {
                    "accion": "guardar",
                    "nombre": "Harinas Leonesas SL",
                    "nif": "B24010101",
                    "domicilio": "Pol. Ind. Leon Oeste 12, Leon",
                    "esCliente": true,
                    "esTransportista": false,
                    "activo": true,
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CLI-00428"
                  }
                },
                "desactivar": {
                  "summary": "Desactivar por referencia del ERP",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CLI-00428"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registro actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Registro creado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteWriteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_clientes_importar.php": {
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "importarEntidades",
        "summary": "Validar o importar clientes y transportistas por lotes",
        "description": "Procesa de 1 a 1000 fichas de forma aislada para la empresa asociada a `X-Api-Key`. Use primero `accion=validar`; `accion=importar` ejecuta todo el lote dentro de una transacción y no guarda ninguna fila si existe un error. Los duplicados se identifican por referencia ERP, NIF o nombre dentro de la misma empresa.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClienteImportacionRequest"
              },
              "examples": {
                "validar": {
                  "summary": "Simular antes de importar",
                  "value": {
                    "accion": "validar",
                    "modoDuplicados": "actualizar",
                    "registros": [
                      {
                        "origenRegistro": "ERP_EMPRESA",
                        "idExterno": "CLI-00428",
                        "nombre": "Harinas Leonesas SL",
                        "nif": "B24010101",
                        "domicilio": "León",
                        "esCliente": true,
                        "esTransportista": false,
                        "activo": true
                      },
                      {
                        "origenRegistro": "ERP_EMPRESA",
                        "idExterno": "TRA-00017",
                        "nombre": "Transportes El Rápido SL",
                        "nif": "B87654321",
                        "esCliente": false,
                        "esTransportista": true,
                        "activo": true
                      }
                    ]
                  }
                },
                "importar": {
                  "summary": "Confirmar un lote ya validado",
                  "value": {
                    "accion": "importar",
                    "modoDuplicados": "actualizar",
                    "registros": [
                      {
                        "origenRegistro": "ERP_EMPRESA",
                        "idExterno": "CLI-00428",
                        "nombre": "Harinas Leonesas SL",
                        "nif": "B24010101",
                        "esCliente": true
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lote validado o importado correctamente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteImportacionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Suscripción caducada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "description": "El lote contiene errores de validación.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteImportacionResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_vehiculos.php": {
      "get": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "consultarVehiculos",
        "summary": "Consultar o listar vehículos",
        "description": "Sin parametros de identificacion devuelve un listado paginado. Para obtener un registro concreto use `id` o la pareja `origen` + `idExterno`.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Identificador interno del vehiculo.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "Sistema que asigno la referencia externa. Debe enviarse junto a idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Identificador estable del registro en el ERP. Debe enviarse junto a origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filtra por estado. El valor predeterminado devuelve activos e inactivos.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busqueda libre en los campos principales y la referencia externa.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Numero maximo de elementos de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Primer elemento de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/VehiculoItemResponse"
                    },
                    {
                      "$ref": "#/components/schemas/VehiculoListResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "guardarVehiculo",
        "summary": "Crear, actualizar, activar o desactivar un vehículo",
        "description": "Use `accion=guardar` para sincronizar de forma idempotente. Si ya existe la pareja `origenRegistro` + `idExterno`, el registro se actualiza; si no existe, se crea. `actualizar`, `activar` y `desactivar` admiten `id` o referencia externa. No se realiza borrado fisico.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VehiculoWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Crear o actualizar vehiculo desde el ERP",
                  "value": {
                    "accion": "guardar",
                    "matricula": "1234 KLM",
                    "tipo": "tractora",
                    "marca": "Volvo",
                    "modelo": "FH 460",
                    "activo": true,
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "VEH-00117"
                  }
                },
                "desactivar": {
                  "summary": "Desactivar por referencia del ERP",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "VEH-00117"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registro actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VehiculoWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Registro creado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VehiculoWriteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_conductores.php": {
      "get": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "consultarConductores",
        "summary": "Consultar o listar conductores",
        "description": "Sin parametros de identificacion devuelve un listado paginado. Para obtener un registro concreto use `id` o la pareja `origen` + `idExterno`.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Identificador interno del conductor.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "Sistema que asigno la referencia externa. Debe enviarse junto a idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Identificador estable del registro en el ERP. Debe enviarse junto a origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filtra por estado. El valor predeterminado devuelve activos e inactivos.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Busqueda libre en los campos principales y la referencia externa.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Numero maximo de elementos de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Primer elemento de la pagina.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ConductorItemResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ConductorListResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "guardarConductor",
        "summary": "Crear, actualizar, activar o desactivar un conductor",
        "description": "Use `accion=guardar` para sincronizar de forma idempotente. Si ya existe la pareja `origenRegistro` + `idExterno`, el registro se actualiza; si no existe, se crea. `actualizar`, `activar` y `desactivar` admiten `id` o referencia externa. No se realiza borrado fisico.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConductorWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Crear o actualizar conductor desde el ERP",
                  "value": {
                    "accion": "guardar",
                    "nombre": "Carlos Martin Gomez",
                    "telefono": "34600111222",
                    "email": "carlos@transportes.test; trafico@transportes.test",
                    "notificarEmail": true,
                    "activo": true,
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CON-00032"
                  }
                },
                "desactivar": {
                  "summary": "Desactivar por referencia del ERP",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CON-00032"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registro actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConductorWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Registro creado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConductorWriteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_lugares.php": {
      "get": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "consultarLugares",
        "summary": "Consultar o listar lugares habituales",
        "description": "Maestro opcional de granjas, almacenes y puntos habituales. La clave API limita siempre la consulta a su empresa.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 50
            },
            "description": "Sistema que asigno la referencia externa; junto a idExterno."
          },
          {
            "name": "idExterno",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Referencia estable del ERP; junto a origen."
          },
          {
            "name": "activo",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "uso",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "origen",
                "destino",
                "ambos"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consulta correcta.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/LugarItemResponse"
                    },
                    {
                      "$ref": "#/components/schemas/LugarListResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "guardarLugar",
        "summary": "Crear, actualizar, activar o desactivar un lugar",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LugarWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Crear o actualizar una granja del ERP",
                  "value": {
                    "accion": "guardar",
                    "codigo": "GR-018",
                    "nombre": "Granja Los Prados",
                    "domicilio": "Camino Rural 4, Segovia",
                    "esOrigen": true,
                    "esDestino": false,
                    "activo": true,
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "GRANJA-018"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registro actualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LugarWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Registro creado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LugarWriteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_descargas.php": {
      "post": {
        "tags": [
          "Descargas"
        ],
        "operationId": "crearLoteDescarga",
        "summary": "Preparar un lote ZIP de PDF",
        "description": "Crea una instantánea de las versiones vigentes. Devuelve HTTP 202 e idLote inmediatamente; el ERP consulta después el estado sin mantener abierta la petición.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fechaCampo": {
                    "type": "string",
                    "enum": [
                      "transporte",
                      "registro",
                      "creacion",
                      "modificacion"
                    ],
                    "default": "transporte"
                  },
                  "fechaDesde": {
                    "type": "string",
                    "format": "date"
                  },
                  "fechaHasta": {
                    "type": "string",
                    "format": "date"
                  },
                  "ids": {
                    "type": "array",
                    "maxItems": 10000,
                    "items": {
                      "type": "integer",
                      "minimum": 1
                    }
                  },
                  "soloPendientes": {
                    "type": "boolean",
                    "default": true,
                    "description": "Excluye las versiones ya descargadas."
                  }
                },
                "description": "Indique un intervalo de fechas o una lista de ids. Máximo 10.000 documentos y 512 MB."
              },
              "example": {
                "fechaCampo": "transporte",
                "fechaDesde": "2026-09-01",
                "fechaHasta": "2026-09-30",
                "soloPendientes": true
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Lote aceptado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoteDescarga"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "tags": [
          "Descargas"
        ],
        "operationId": "consultarDescargarLote",
        "summary": "Consultar el estado o descargar un lote",
        "description": "Con accion=estado avanza la preparación por bloques y devuelve el progreso. Repita la consulta hasta estado=disponible. Con accion=descargar entrega el ZIP y registra la descarga de cada versión. El ZIP caduca 24 horas después de estar disponible.",
        "parameters": [
          {
            "name": "accion",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "estado",
                "descargar"
              ]
            }
          },
          {
            "name": "idLote",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Estado JSON o archivo ZIP, según accion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoteDescarga"
                }
              },
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "410": {
            "description": "El ZIP temporal ha caducado."
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_usuarios.php": {
      "get": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "listarUsuariosApi",
        "summary": "Listar usuarios y estado de sus claves personales",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Usuarios sin mostrar claves completas."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Maestros ERP"
        ],
        "operationId": "administrarUsuariosApi",
        "summary": "Importar usuarios o regenerar/revocar una clave personal",
        "description": "Requiere X-Api-Key. Las claves completas solo aparecen en la respuesta que las genera.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "accion": "importar",
                "usuarios": [
                  {
                    "usuario": "operador1",
                    "clave": "ClaveWebSegura",
                    "activo": true,
                    "accesoTodosDeca": true,
                    "soloPropiosDeca": true,
                    "generarApiKey": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Operación completada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "Clave de 32 caracteres asignada a la empresa. Trátela como una contraseña y no la incluya en URLs ni registros de diagnóstico."
      },
      "UserApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-User-Api-Key",
        "description": "Clave personal que identifica simultáneamente empresa y usuario. No se envía junto con X-Api-Key."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Petición incorrecta o datos incompletos",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "fechaTransporte debe ser YYYY-MM-DD."
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Clave API ausente o no válida",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "Clave API no válida."
            }
          }
        }
      },
      "Forbidden": {
        "description": "La empresa no tiene la API disponible o la suscripción ha caducado",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "Suscripción caducada."
            }
          }
        }
      },
      "NotFound": {
        "description": "Registro no encontrado para la empresa autenticada.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "DeCA no encontrado."
            }
          }
        }
      },
      "Conflict": {
        "description": "Ya existe un registro con los mismos datos o referencia externa.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "Ya existe un DeCA para origen 'ERP_CLIENTE' / idExterno 'EXP-12345'. Use 'actualizar'."
            }
          }
        }
      },
      "ServerError": {
        "description": "No se pudo completar la operación",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "No se pudo completar la operación."
            }
          }
        }
      }
    },
    "schemas": {
      "LoteDescarga": {
        "type": "object",
        "required": [
          "ok",
          "idLote",
          "estado",
          "totalDocumentos",
          "procesados",
          "porcentaje"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          },
          "idLote": {
            "type": "string",
            "format": "uuid"
          },
          "estado": {
            "type": "string",
            "enum": [
              "preparando",
              "disponible",
              "error",
              "caducado"
            ]
          },
          "totalDocumentos": {
            "type": "integer",
            "example": 326
          },
          "procesados": {
            "type": "integer",
            "example": 180
          },
          "porcentaje": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "tamanoBytes": {
            "type": "integer",
            "format": "int64"
          },
          "fechaSolicitud": {
            "type": "string",
            "format": "date-time"
          },
          "fechaDisponible": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "caduca": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "urlEstado": {
            "type": "string",
            "format": "uri"
          },
          "urlDescarga": {
            "type": "string",
            "format": "uri",
            "description": "Solo aparece cuando estado es disponible. Requiere la misma X-Api-Key."
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "LineaMercancia": {
        "type": "object",
        "description": "Línea de mercancía transportada.",
        "properties": {
          "descripcion": {
            "type": "string",
            "maxLength": 200,
            "description": "Naturaleza de la mercancía."
          },
          "cantidad": {
            "type": "number",
            "minimum": 0,
            "nullable": true,
            "description": "Cantidad en la unidad indicada."
          },
          "unidad": {
            "type": "string",
            "maxLength": 30,
            "nullable": true,
            "description": "Unidad de medida: palets, bultos, sacos, m3, etc."
          },
          "pesoKg": {
            "type": "number",
            "minimum": 0,
            "nullable": true,
            "description": "Peso de la línea en kilogramos."
          }
        }
      },
      "DecaInputFields": {
        "type": "object",
        "properties": {
          "idCliente": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Entidad con rol cliente. En una actualización puede enviarse 0 o null para eliminar la vinculación."
          },
          "idTransportista": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Entidad con rol transportista. En una actualización puede enviarse 0 o null para eliminar la vinculación."
          },
          "cargadorNombre": {
            "type": "string",
            "description": "Nombre o razón social del cargador contractual. Obligatorio cuando hay fecha de transporte."
          },
          "cargadorNif": {
            "type": "string",
            "description": "NIF/CIF del cargador contractual. Obligatorio cuando hay fecha de transporte."
          },
          "cargadorDomicilio": {
            "type": "string",
            "description": "Domicilio del cargador contractual. Obligatorio cuando hay fecha de transporte."
          },
          "transportistaNombre": {
            "type": "string",
            "description": "Si se omite, se usa el nombre configurado para la empresa."
          },
          "transportistaNif": {
            "type": "string",
            "description": "Si se omite, se usa el NIF configurado para la empresa."
          },
          "origen": {
            "type": "string",
            "maxLength": 512,
            "description": "Lugar de origen. Obligatorio cuando hay fecha de transporte."
          },
          "destino": {
            "type": "string",
            "maxLength": 512,
            "description": "Lugar de destino. Obligatorio cuando hay fecha de transporte."
          },
          "fechaTransporte": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Fecha del viaje en formato YYYY-MM-DD. Omítala o envíe una cadena vacía para dejar el viaje no planificado."
          },
          "matriculaTractora": {
            "type": "string",
            "nullable": true,
            "description": "Matrícula del vehículo principal, si se conoce. En una actualización puede enviarse vacía o null para eliminarla."
          },
          "matriculaRemolque": {
            "type": "string",
            "nullable": true,
            "description": "Matrícula del remolque, si existe. En una actualización puede enviarse vacía para eliminarla."
          },
          "observaciones": {
            "type": "string",
            "nullable": true
          },
          "numAlbaran": {
            "type": "string",
            "nullable": true,
            "description": "Número de albarán. En un alta, si se informa, el documento queda marcado como albaranado."
          },
          "anulado": {
            "type": "boolean",
            "description": "Estado opcional, utilizado principalmente en actualizaciones."
          },
          "terminado": {
            "type": "boolean",
            "description": "Estado opcional, utilizado principalmente en actualizaciones."
          },
          "albaranado": {
            "type": "boolean",
            "description": "Estado opcional, utilizado principalmente en actualizaciones."
          },
          "origenRegistro": {
            "type": "string",
            "nullable": true,
            "description": "Código estable del sistema que origina el registro, por ejemplo `ERP_CLIENTE`."
          },
          "idExterno": {
            "type": "string",
            "nullable": true,
            "description": "Identificador estable del correo, pedido o expedición. Máximo 512 unidades UTF-16; no se recorta. Junto con origenRegistro es único por empresa.",
            "maxLength": 512
          },
          "modoEdicionTransportista": {
            "type": "string",
          "enum": [
            "operativo",
            "ruta",
            "carga",
            "completo"
          ],
            "default": "operativo",
            "description": "Permisos del enlace privado. `operativo`: fecha y matrículas. `ruta`: añade origen y destino. `carga`: añade mercancía. `completo`: permite ruta y mercancía. No autoriza cambios en empresas, NIF ni estados administrativos."
          },
          "diasValidezEnlace": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90,
            "default": 30,
            "description": "Días de validez cuando sea necesario crear un enlace nuevo. Recuperar un enlace activo no cambia su token ni su caducidad."
          },
          "lineas": {
            "type": "array",
            "description": "Mercancías del viaje. Con fecha debe existir al menos una línea con descripción y, en alguna línea, `pesoKg` o `cantidad` + `unidad`. En una actualización, enviar esta propiedad sustituye todas las líneas anteriores.",
            "items": {
              "$ref": "#/components/schemas/LineaMercancia"
            }
          },
          "mercancia": {
            "type": "string",
            "deprecated": true,
            "description": "Campo de compatibilidad para crear una sola línea. En integraciones nuevas use `lineas`."
          },
          "pesoKg": {
            "type": "number",
            "minimum": 0,
            "deprecated": true,
            "description": "Campo de compatibilidad asociado a `mercancia`."
          },
          "otraMagnitud": {
            "type": "string",
            "deprecated": true,
            "description": "Campo de compatibilidad asociado a `mercancia`."
          },
          "idConductor": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Forma abreviada para asignar un conductor. Use conductores para asignar dos."
          },
          "notaConductorDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Nota propia del conductor abreviado en este viaje."
          },
          "mostrarNotaConductorDeca": {
            "type": "boolean",
            "description": "Muestra la nota del conductor abreviado en el PDF."
          },
          "conductores": {
            "type": "array",
            "minItems": 0,
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/ConductorDeca"
            },
            "description": "Opcional. Sustituye todas las asignaciones. Omitir en actualización conserva los conductores; [] los elimina. Admite idConductor (formato anterior) o nombre y contactos para un puntual. No modifica fichas."
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "description": "Incluye el nombre y las notas autorizadas en el PDF. En un alta se hereda del cliente si se omite. Nunca incluye DNI, telefono ni email."
          },
          "idLugarOrigen": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Lugar habitual de origen de la misma empresa. Si se indica, la API copia su nombre y domicilio al viaje."
          },
          "idLugarDestino": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Lugar habitual de destino de la misma empresa. Si se indica, la API copia su nombre y domicilio al viaje."
          }
        }
      },
      "DecaCreateRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DecaInputFields"
          },
          {
            "type": "object",
            "required": [
              "accion"
            ],
            "properties": {
              "accion": {
                "type": "string",
                "enum": [
                  "crear"
                ]
              }
            }
          }
        ]
      },
      "DecaUpdateRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DecaInputFields"
          },
          {
            "type": "object",
            "required": [
              "accion",
              "id"
            ],
            "properties": {
              "accion": {
                "type": "string",
                "enum": [
                  "actualizar"
                ]
              },
              "id": {
                "type": "integer",
                "minimum": 1,
                "description": "Identificador `idDeca` que se va a modificar."
              }
            }
          }
        ]
      },
      "EstadoDeca": {
        "type": "object",
        "properties": {
          "anulado": {
            "type": "boolean"
          },
          "terminado": {
            "type": "boolean"
          },
          "albaranado": {
            "type": "boolean"
          },
          "numAlbaran": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "EnvioReparto": {
        "type": "object",
        "required": [
          "lineas"
        ],
        "properties": {
          "referencia": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Pedido, expedición o entrega del ERP."
          },
          "origen": {
            "type": "string",
            "maxLength": 512
          },
          "destino": {
            "type": "string",
            "maxLength": 512
          },
          "observaciones": {
            "type": "string",
            "maxLength": 300,
            "nullable": true
          },
          "lineas": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/LineaMercancia"
            }
          },
          "idLugarOrigen": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Lugar habitual de origen de la misma empresa. Si se indica, la API copia su nombre y domicilio al viaje."
          },
          "idLugarDestino": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Lugar habitual de destino de la misma empresa. Si se indica, la API copia su nombre y domicilio al viaje."
          }
        },
        "description": "origen y destino pueden escribirse manualmente o resolverse con idLugarOrigen e idLugarDestino. Con fecha de transporte, cada envio debe tener ambos textos o identificadores validos."
      },
      "RepartoResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/DecaWriteResponse"
          },
          {
            "type": "object",
            "required": [
              "reparto",
              "numeroEnvios",
              "envios"
            ],
            "properties": {
              "reparto": {
                "type": "boolean"
              },
              "numeroEnvios": {
                "type": "integer",
                "minimum": 1
              },
              "envios": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EnvioReparto"
                }
              }
            }
          }
        ]
      },
      "Cumplimentacion": {
        "type": "object",
        "properties": {
          "urlEdicion": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "modoEdicionTransportista": {
            "type": "string",
            "enum": [
              "operativo",
              "ruta",
              "carga",
              "completo"
            ],
            "nullable": true
          },
          "camposEditables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "estadoCumplimentacion": {
            "type": "string",
            "enum": [
              "no_iniciado",
              "pendiente",
              "completado",
              "cerrado"
            ]
          },
          "fechaUltimoGuardado": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaFinalizacion": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaCaducidadEnlace": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "enlaceActivo": {
            "type": "boolean"
          }
        }
      },
      "EnlaceEdicionResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Cumplimentacion"
          },
          {
            "type": "object",
            "required": [
              "ok",
              "idDeca",
              "estadoCumplimentacion",
              "enlaceActivo"
            ],
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "idDeca": {
                "type": "integer"
              },
              "idCliente": {
                "type": "integer",
                "nullable": true
              },
              "idTransportista": {
                "type": "integer",
                "nullable": true
              },
              "numVersion": {
                "type": "integer",
                "nullable": true
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "urlDocumento": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "urlDescargaPdf": {
                "type": "string",
                "format": "uri",
                "nullable": true
              },
              "pdfDisponible": {
                "type": "boolean"
              },
              "numeroEmpresa": {
                "type": "integer",
                "format": "int64",
                "minimum": 1,
                "readOnly": true,
                "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
              }
            }
          }
        ]
      },
      "DecaWriteResponse": {
        "type": "object",
        "required": [
          "ok",
          "idDeca",
          "token",
          "url",
          "pdf"
        ],
        "properties": {
          "idCliente": {
            "type": "integer",
            "nullable": true
          },
          "idTransportista": {
            "type": "integer",
            "nullable": true
          },
          "ok": {
            "type": "boolean"
          },
          "idDeca": {
            "type": "integer"
          },
          "token": {
            "type": "string",
            "description": "Token técnico de la URL documental. La integración debe conservar `idDeca`, `urlEdicion` y su referencia externa."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Campo legado: URL estable del documento. Puede no estar disponible hasta que exista PDF. Para nuevas integraciones use `urlDocumento` y `urlEdicion`."
          },
          "urlDocumento": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Vista pública del DeCA vigente. Es nula mientras no exista una versión PDF."
          },
          "urlDescargaPdf": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Endpoint autenticado que descarga el PDF vigente con `X-Api-Key`."
          },
          "pdfDisponible": {
            "type": "boolean"
          },
          "urlEdicion": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Enlace privado que se puede incluir en la orden enviada al transportista. No requiere clave API."
          },
          "modoEdicionTransportista": {
            "type": "string",
            "enum": [
              "operativo",
              "ruta",
              "carga",
              "completo"
            ],
            "nullable": true
          },
          "camposEditables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "estadoCumplimentacion": {
            "type": "string",
            "enum": [
              "no_iniciado",
              "pendiente",
              "completado",
              "cerrado"
            ]
          },
          "fechaUltimoGuardado": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaFinalizacion": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaCaducidadEnlace": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "enlaceActivo": {
            "type": "boolean"
          },
          "numVersion": {
            "type": "integer",
            "nullable": true,
            "description": "Es nulo mientras el viaje no tenga fecha ni PDF."
          },
          "pdf": {
            "type": "boolean",
            "description": "Indica si se generó una versión PDF en esta operación."
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
          },
          "incluirConductorPdf": {
            "type": "boolean"
          },
          "conductores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConductorDecaRespuesta"
            }
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del expedidor."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del destinatario."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del transportista o conductor."
          }
        }
      },
      "DecaConsultaResponse": {
        "type": "object",
        "required": [
          "ok",
          "idDeca",
          "url",
          "estado",
          "lineas"
        ],
        "properties": {
          "idCliente": {
            "type": "integer",
            "nullable": true
          },
          "idTransportista": {
            "type": "integer",
            "nullable": true
          },
          "ok": {
            "type": "boolean"
          },
          "idDeca": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "urlDocumento": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "urlDescargaPdf": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "pdfDisponible": {
            "type": "boolean"
          },
          "urlEdicion": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "modoEdicionTransportista": {
            "type": "string",
          "enum": [
            "operativo",
            "ruta",
            "carga",
            "completo"
          ],
            "nullable": true
          },
          "camposEditables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "estadoCumplimentacion": {
            "type": "string",
            "enum": [
              "no_iniciado",
              "pendiente",
              "completado",
              "cerrado"
            ]
          },
          "fechaUltimoGuardado": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaFinalizacion": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "fechaCaducidadEnlace": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "enlaceActivo": {
            "type": "boolean"
          },
          "numVersion": {
            "type": "integer",
            "nullable": true
          },
          "fechaTransporte": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "matriculaTractora": {
            "type": "string",
            "maxLength": 15,
            "nullable": true,
            "description": "Matrícula tractora actual. Es null si todavía no se ha asignado."
          },
          "matriculaRemolque": {
            "type": "string",
            "maxLength": 15,
            "nullable": true,
            "description": "Matrícula de remolque actual. Es null si no corresponde o aún no se ha asignado."
          },
          "estado": {
            "$ref": "#/components/schemas/EstadoDeca"
          },
          "origenRegistro": {
            "type": "string",
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "nullable": true,
            "maxLength": 512,
            "description": "Identificador estable del correo, pedido o expedición. Máximo 512 unidades UTF-16; no se recorta. Junto con origenRegistro es único por empresa."
          },
          "lineas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineaMercancia"
            }
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
          },
          "incluirConductorPdf": {
            "type": "boolean"
          },
          "conductores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConductorDecaRespuesta"
            }
          },
          "envios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvioReparto"
            },
            "description": "Rutas y mercancias estructuradas. Incluye los identificadores de lugares habituales cuando se utilizaron."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del expedidor."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del destinatario."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "description": "Indica si el PDF incluye la zona de firma del transportista o conductor."
          }
        }
      },
      "DecaBusquedaResponse": {
        "type": "object",
        "required": [
          "ok",
          "encontrado"
        ],
        "properties": {
          "idCliente": {
            "type": "integer",
            "nullable": true
          },
          "idTransportista": {
            "type": "integer",
            "nullable": true
          },
          "ok": {
            "type": "boolean"
          },
          "encontrado": {
            "type": "boolean"
          },
          "idDeca": {
            "type": "integer",
            "nullable": true
          },
          "url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "numVersion": {
            "type": "integer",
            "nullable": true
          },
          "fechaTransporte": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
          }
        }
      },
      "DecaListadoItem": {
        "type": "object",
        "properties": {
          "idCliente": {
            "type": "integer",
            "nullable": true
          },
          "idTransportista": {
            "type": "integer",
            "nullable": true
          },
          "idDeca": {
            "type": "integer"
          },
          "fechaTransporte": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "cargadorNombre": {
            "type": "string",
            "nullable": true
          },
          "origen": {
            "type": "string",
            "nullable": true
          },
          "destino": {
            "type": "string",
            "nullable": true
          },
          "mercancia": {
            "type": "string",
            "nullable": true
          },
          "numVersion": {
            "type": "integer",
            "nullable": true
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "urlDocumento": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "urlDescargaPdf": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "pdfDisponible": {
            "type": "boolean"
          },
          "cumplimentacion": {
            "$ref": "#/components/schemas/Cumplimentacion"
          },
          "fechaCreacion": {
            "type": "string",
            "nullable": true,
            "example": "2026-08-20 09:30"
          },
          "fechaModificacion": {
            "type": "string",
            "nullable": true,
            "example": "2026-08-20 10:15"
          },
          "fechaRegistro": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "origenRegistro": {
            "type": "string",
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "nullable": true,
            "maxLength": 512,
            "description": "Identificador estable del correo, pedido o expedición. Máximo 512 unidades UTF-16; no se recorta. Junto con origenRegistro es único por empresa."
          },
          "estado": {
            "$ref": "#/components/schemas/EstadoDeca"
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Numero de DeCA consecutivo e inmutable por empresa. Solo lectura. No sustituye al ID global utilizado en peticiones y URLs."
          }
        }
      },
      "DecaListadoResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "limit",
          "offset",
          "fechaCampo",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer",
            "description": "Total de registros que cumplen el filtro."
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "fechaCampo": {
            "type": "string",
            "enum": [
              "creacion",
              "modificacion",
              "registro",
              "transporte"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DecaListadoItem"
            }
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string",
            "description": "Mensaje legible que indica la causa del error."
          }
        }
      },
      "ClienteImportacionRegistro": {
        "type": "object",
        "required": [
          "nombre",
          "nif"
        ],
        "properties": {
          "nombre": {
            "type": "string",
            "maxLength": 150
          },
          "nif": {
            "type": "string",
            "maxLength": 20
          },
          "domicilio": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "esCliente": {
            "type": "boolean",
            "default": true
          },
          "esTransportista": {
            "type": "boolean",
            "default": false
          },
          "activo": {
            "type": "boolean",
            "default": true
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Preferencia que se copia a cada nuevo DeCA del cliente."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del expedidor al pie de los nuevos DeCA."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del destinatario al pie de los nuevos DeCA."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del transportista o conductor al pie de los nuevos DeCA."
          }
        }
      },
      "ClienteImportacionRequest": {
        "type": "object",
        "required": [
          "accion",
          "registros"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "validar",
              "importar"
            ],
            "default": "validar"
          },
          "modoDuplicados": {
            "type": "string",
            "enum": [
              "actualizar",
              "omitir"
            ],
            "default": "actualizar"
          },
          "registros": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1000,
            "items": {
              "$ref": "#/components/schemas/ClienteImportacionRegistro"
            }
          }
        }
      },
      "ClienteImportacionResumen": {
        "type": "object",
        "required": [
          "total",
          "crear",
          "actualizar",
          "omitir",
          "errores"
        ],
        "properties": {
          "total": {
            "type": "integer"
          },
          "crear": {
            "type": "integer"
          },
          "actualizar": {
            "type": "integer"
          },
          "omitir": {
            "type": "integer"
          },
          "errores": {
            "type": "integer"
          }
        }
      },
      "ClienteImportacionFila": {
        "type": "object",
        "required": [
          "fila",
          "accion"
        ],
        "properties": {
          "fila": {
            "type": "integer"
          },
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "omitir",
              "error"
            ]
          },
          "idCliente": {
            "type": "integer",
            "nullable": true
          },
          "nombre": {
            "type": "string",
            "nullable": true
          },
          "nif": {
            "type": "string",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ClienteImportacionResponse": {
        "type": "object",
        "required": [
          "ok",
          "importado",
          "valido",
          "resumen",
          "filas"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "importado": {
            "type": "boolean"
          },
          "valido": {
            "type": "boolean"
          },
          "resumen": {
            "$ref": "#/components/schemas/ClienteImportacionResumen"
          },
          "filas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClienteImportacionFila"
            }
          }
        }
      },
      "ClienteWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar",
            "description": "`guardar` es la opcion recomendada para sincronizacion ERP porque crea o actualiza por referencia externa."
          },
          "id": {
            "type": "integer",
            "minimum": 1,
            "description": "Id interno, necesario si no se usa referencia externa."
          },
          "nombre": {
            "type": "string",
            "maxLength": 150
          },
          "nif": {
            "type": "string",
            "maxLength": 20
          },
          "domicilio": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "esCliente": {
            "type": "boolean",
            "default": true,
            "description": "Permite seleccionar la entidad como cargador contractual."
          },
          "esTransportista": {
            "type": "boolean",
            "default": false,
            "description": "Permite seleccionar la entidad como transportista efectivo."
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Preferencia que se copia a cada nuevo DeCA del cliente."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del expedidor al pie de los nuevos DeCA."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del destinatario al pie de los nuevos DeCA."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del transportista o conductor al pie de los nuevos DeCA."
          }
        }
      },
      "VehiculoWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar",
            "description": "`guardar` es la opcion recomendada para sincronizacion ERP porque crea o actualiza por referencia externa."
          },
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "matricula": {
            "type": "string",
            "maxLength": 15
          },
          "tipo": {
            "type": "string",
            "enum": [
              "tractora",
              "remolque",
              "rigido",
              "otro"
            ],
            "default": "tractora"
          },
          "marca": {
            "type": "string",
            "maxLength": 60,
            "nullable": true
          },
          "modelo": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          }
        }
      },
      "ConductorWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar",
            "description": "`guardar` es la opcion recomendada para sincronizacion ERP porque crea o actualiza por referencia externa."
          },
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "nombre": {
            "type": "string",
            "maxLength": 150
          },
          "telefono": {
            "type": "string",
            "description": "Se conserva exactamente el texto recibido, sin añadir prefijos ni eliminar espacios, signos o guiones. Máximo 20 caracteres.",
            "maxLength": 20
          },
          "email": {
            "type": "string",
            "maxLength": 500,
            "nullable": true,
            "description": "Una o varias direcciones validas separadas por punto y coma. Se admiten hasta 10."
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "Si es true, notifica automaticamente al crear el DeCA pendiente y al quedar completo. Requiere email."
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Nota operativa propuesta para los nuevos DeCA del conductor."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "default": false,
            "description": "Propone mostrar notaDeca junto al nombre en los nuevos DeCA."
          }
        }
      },
      "ClienteItem": {
        "type": "object",
        "properties": {
          "idCliente": {
            "type": "integer"
          },
          "nombre": {
            "type": "string"
          },
          "nif": {
            "type": "string"
          },
          "domicilio": {
            "type": "string",
            "nullable": true
          },
          "esCliente": {
            "type": "boolean"
          },
          "esTransportista": {
            "type": "boolean"
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Preferencia que se copia a cada nuevo DeCA del cliente."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del expedidor al pie de los nuevos DeCA."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del destinatario al pie de los nuevos DeCA."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Añade una zona de firma del transportista o conductor al pie de los nuevos DeCA."
          }
        }
      },
      "VehiculoItem": {
        "type": "object",
        "properties": {
          "idVehiculo": {
            "type": "integer"
          },
          "matricula": {
            "type": "string"
          },
          "tipo": {
            "type": "string",
            "enum": [
              "tractora",
              "remolque",
              "rigido",
              "otro"
            ]
          },
          "marca": {
            "type": "string",
            "nullable": true
          },
          "modelo": {
            "type": "string",
            "nullable": true
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConductorItem": {
        "type": "object",
        "properties": {
          "idConductor": {
            "type": "integer"
          },
          "nombre": {
            "type": "string"
          },
          "telefono": {
            "type": "string",
            "description": "Se conserva exactamente el texto recibido, sin añadir prefijos ni eliminar espacios, signos o guiones. Máximo 20 caracteres.",
            "maxLength": 20
          },
          "email": {
            "type": "string",
            "nullable": true,
            "description": "Direcciones separadas por punto y coma."
          },
          "notificarEmail": {
            "type": "boolean"
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Codigo estable del sistema origen. Debe enviarse junto a idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Identificador estable en el ERP. Debe enviarse junto a origenRegistro."
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Nota operativa propuesta para los nuevos DeCA del conductor."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "default": false,
            "description": "Propone mostrar notaDeca junto al nombre en los nuevos DeCA."
          }
        }
      },
      "ClienteItemResponse": {
        "type": "object",
        "required": [
          "ok",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/ClienteItem"
          }
        }
      },
      "ClienteWriteResponse": {
        "type": "object",
        "required": [
          "ok",
          "creado",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "creado": {
            "type": "boolean",
            "description": "true si se creo; false si se actualizo."
          },
          "item": {
            "$ref": "#/components/schemas/ClienteItem"
          }
        }
      },
      "ClienteListResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "limit",
          "offset",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClienteItem"
            }
          }
        }
      },
      "VehiculoItemResponse": {
        "type": "object",
        "required": [
          "ok",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/VehiculoItem"
          }
        }
      },
      "VehiculoWriteResponse": {
        "type": "object",
        "required": [
          "ok",
          "creado",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "creado": {
            "type": "boolean",
            "description": "true si se creo; false si se actualizo."
          },
          "item": {
            "$ref": "#/components/schemas/VehiculoItem"
          }
        }
      },
      "VehiculoListResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "limit",
          "offset",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VehiculoItem"
            }
          }
        }
      },
      "ConductorItemResponse": {
        "type": "object",
        "required": [
          "ok",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/ConductorItem"
          }
        }
      },
      "ConductorWriteResponse": {
        "type": "object",
        "required": [
          "ok",
          "creado",
          "item"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "creado": {
            "type": "boolean",
            "description": "true si se creo; false si se actualizo."
          },
          "item": {
            "$ref": "#/components/schemas/ConductorItem"
          }
        }
      },
      "ConductorListResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "limit",
          "offset",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConductorItem"
            }
          }
        }
      },
      "ConductorDeca": {
        "type": "object",
        "properties": {
          "idConductor": {
            "type": "integer",
            "minimum": 0,
            "nullable": true
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Nota operativa propia del viaje. No incluya DNI, telefono, email ni datos privados innecesarios."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "description": "Muestra notaDeca junto al nombre del conductor cuando incluirConductorPdf es true."
          },
          "nombre": {
            "type": "string",
            "maxLength": 100,
            "description": "Obligatorio para conductor puntual sin idConductor."
          },
          "telefono": {
            "type": "string",
            "nullable": true,
            "maxLength": 20,
            "description": "Se conserva exactamente el texto recibido, sin añadir prefijos ni eliminar espacios, signos o guiones. Máximo 20 caracteres."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "maxLength": 500
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "Para este DeCA. Si es true requiere email válido. En conductor puntual, true por defecto."
          }
        },
        "description": "Hasta dos conductores. Indique idConductor para copiar una ficha, o nombre para un conductor puntual. Los datos enviados se guardan solo en este DeCA y no modifican la ficha general."
      },
      "LugarWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar"
          },
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "codigo": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "nombre": {
            "type": "string",
            "minLength": 1,
            "maxLength": 150
          },
          "domicilio": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "esOrigen": {
            "type": "boolean",
            "default": true
          },
          "esDestino": {
            "type": "boolean",
            "default": false
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          }
        },
        "description": "Debe estar habilitado al menos para origen o destino. Use guardar con origenRegistro e idExterno para sincronizacion idempotente."
      },
      "LugarItem": {
        "type": "object",
        "properties": {
          "idLugar": {
            "type": "integer"
          },
          "codigo": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "nombre": {
            "type": "string"
          },
          "domicilio": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "esOrigen": {
            "type": "boolean"
          },
          "esDestino": {
            "type": "boolean"
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "LugarItemResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/LugarItem"
          }
        }
      },
      "LugarWriteResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "creado": {
            "type": "boolean"
          },
          "item": {
            "$ref": "#/components/schemas/LugarItem"
          }
        }
      },
      "LugarListResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LugarItem"
            }
          }
        }
      },
      "ConductorDecaRespuesta": {
        "type": "object",
        "properties": {
          "idConductor": {
            "type": "integer",
            "minimum": 0,
            "nullable": true
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Nota operativa propia del viaje. No incluya DNI, telefono, email ni datos privados innecesarios."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "description": "Muestra notaDeca junto al nombre del conductor cuando incluirConductorPdf es true."
          },
          "nombre": {
            "type": "string",
            "maxLength": 100,
            "description": "Obligatorio para conductor puntual sin idConductor."
          },
          "telefono": {
            "type": "string",
            "nullable": true,
            "maxLength": 20,
            "description": "Se conserva exactamente el texto recibido, sin añadir prefijos ni eliminar espacios, signos o guiones. Máximo 20 caracteres."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "maxLength": 500
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "Para este DeCA. Si es true requiere email válido. En conductor puntual, true por defecto."
          },
          "orden": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2
          }
        },
        "description": "Datos del conductor guardados en el documento. idConductor es null para conductores puntuales."
      }
    }
  }
}
