{
  "openapi": "3.0.3",
  "info": {
    "title": "DECA ERP API",
    "version": "1.8.0",
    "description": "REST API for integrating DECA ERP with invoicing, dispatch and fleet management systems. Create incomplete trips, immediately obtain a private completion link, check their status, download the current PDF, synchronize master data, batch-import customers and manage multi-shipment trips.\n\nAlways send authentication in the `X-Api-Key` header. Test requests operate on the company linked to that key.",
    "contact": {
      "name": "DECA ERP support",
      "email": "soporte@decaerp.com",
      "url": "https://decaerp.com/integracion-erp.html"
    },
    "license": {
      "name": "Use subject to the terms of service",
      "url": "https://decaerp.com/legal.php"
    }
  },
  "externalDocs": {
    "description": "ERP integration guide, examples and demo project",
    "url": "https://decaerp.com/integracion-erp.html"
  },
  "servers": [
    {
      "url": "https://decaerp.com",
      "description": "DECA ERP server"
    },
    {
      "url": "https://deca.netsistemas.com",
      "description": "Legacy domain for existing integrations"
    }
  ],
  "tags": [
    {
      "name": "Write operations",
      "description": "Create and update DeCA documents. The JSON `accion` field selects the operation."
    },
    {
      "name": "Read operations",
      "description": "Individual retrieval, ERP reference searches and filtered lists."
    },
    {
      "name": "History",
      "description": "Immutable PDF versions and change auditing for each document."
    },
    {
      "name": "Downloads",
      "description": "Asynchronous ZIP batch preparation and status tracking."
    },
    {
      "name": "Carrier completion",
      "description": "Private links for the carrier to complete and submit the permitted details."
    },
    {
      "name": "Multi-stop trips",
      "description": "Multi-shipment documents. Each shipment identifies its origin, destination, reference and goods lines."
    },
    {
      "name": "ERP master data",
      "description": "Idempotent synchronization of customers, carriers, vehicles and drivers using `origenRegistro` and `idExterno`."
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "UserApiKeyAuth": []
    }
  ],
  "paths": {
    "/api.php": {
      "post": {
        "tags": [
          "Write operations"
        ],
        "operationId": "escribirDeca",
        "summary": "Create or update a DeCA",
        "description": "Use `accion=crear` to create and `accion=actualizar` with `id` to update a document. Updates behave like PATCH: omitted fields are preserved. Including `lineas` replaces all existing goods lines.\n\nCreation without `fechaTransporte` leaves the trip unscheduled with no PDF yet, but the response already includes `urlEdicion`. The `modoEdicionTransportista` permission is stored on the server: `operativo` allows date and registrations; `carga` also allows goods description, quantity, unit and weight. The carrier can save drafts and submit completion; the ERP checks `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": "Create a trip with a date and goods",
                  "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": "Create an unscheduled trip",
                  "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": "Assign a date to an unscheduled trip",
                  "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": "Change vehicle without altering other details",
                  "value": {
                    "accion": "actualizar",
                    "id": 125,
                    "matriculaTractora": "7350 LPD",
                    "matriculaRemolque": "R 8841 LHG",
                    "observaciones": "Cambio de tractora comunicado desde el ERP"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Document created or updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecaWriteResponse"
                },
                "examples": {
                  "conPdf": {
                    "summary": "Dated trip",
                    "value": {
                      "ok": true,
                      "idDeca": 125,
                      "token": "00000000000000000000000000000000",
                      "url": "https://decaerp.com/deca.php?t=00000000000000000000000000000000",
                      "numVersion": 1,
                      "pdf": true
                    }
                  },
                  "sinPdf": {
                    "summary": "Unscheduled trip",
                    "value": {
                      "ok": true,
                      "idDeca": 126,
                      "token": "00000000000000000000000000000000",
                      "url": "https://decaerp.com/deca.php?t=00000000000000000000000000000000",
                      "urlDocumento": null,
                      "urlDescargaPdf": null,
                      "urlEdicion": "https://decaerp.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": [
          "Read operations"
        ],
        "operationId": "consultarDeca",
        "summary": "Retrieve, find or list DeCAs",
        "description": "The `accion` parameter selects the query:\n\n- `consultar`: retrieves a document by `id`, including completion status.\n- `enlace_edicion`: returns the same active private link or creates one if none exists.\n- `buscar`: finds the ERP-linked document using `origen` and `idExterno`.\n- `listar`: returns a page of results and accepts optional dates.\n\nTo list unscheduled trips, use `noPlanificados=1`. Do not filter by transport date in this case, as those trips have no transport date.",
        "parameters": [
          {
            "name": "accion",
            "in": "query",
            "required": true,
            "description": "Type of query to execute.",
            "schema": {
              "type": "string",
              "enum": [
                "consultar",
                "enlace_edicion",
                "buscar",
                "listar"
              ]
            },
            "example": "listar"
          },
          {
            "name": "id",
            "in": "query",
            "description": "DeCA identifier. Required for `accion=consultar` or `accion=enlace_edicion`.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 125
          },
          {
            "name": "modoEdicionTransportista",
            "in": "query",
            "description": "Link permission. Only for `accion=enlace_edicion`; does not reopen completed links.",
            "schema": {
              "type": "string",
              "enum": [
                "operativo",
                "carga"
              ],
              "default": "operativo"
            }
          },
          {
            "name": "diasValidezEnlace",
            "in": "query",
            "description": "Validity of a new link. Only for `accion=enlace_edicion`.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90,
              "default": 30
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "Stable source-system code. Required for `accion=buscar`.",
            "schema": {
              "type": "string"
            },
            "example": "ERP_CLIENTE"
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "ERP shipment, dispatch or delivery-note identifier. Required for `accion=buscar`.",
            "schema": {
              "type": "string",
              "maxLength": 512
            },
            "example": "EXP-12345"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records. Only for `accion=listar`.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "First record of the page. Only for `accion=listar`.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "fechaCampo",
            "in": "query",
            "description": "Date field used by `fechaDesde` and `fechaHasta`. Only for `accion=listar`.",
            "schema": {
              "type": "string",
              "enum": [
                "creacion",
                "modificacion",
                "registro",
                "transporte"
              ],
              "default": "creacion"
            }
          },
          {
            "name": "fechaDesde",
            "in": "query",
            "description": "Inclusive start date. Optional and usable without an end date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-08-01"
          },
          {
            "name": "fechaHasta",
            "in": "query",
            "description": "Inclusive end date. Optional and usable without a start date.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-08-31"
          },
          {
            "name": "noPlanificados",
            "in": "query",
            "description": "Use `1` to return only trips without `fechaTransporte`. Only for `accion=listar`.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful query. The structure depends on `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": "Query result by ID",
                    "value": {
                      "ok": true,
                      "idDeca": 125,
                      "url": "https://decaerp.com/deca.php?t=00000000000000000000000000000000",
                      "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": "ERP reference not found",
                    "value": {
                      "ok": true,
                      "encontrado": false
                    }
                  },
                  "listado": {
                    "summary": "Results page",
                    "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://decaerp.com/deca.php?t=00000000000000000000000000000000",
                          "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": [
          "History"
        ],
        "operationId": "consultarVersionesDeca",
        "summary": "Get history or download a PDF version",
        "description": "Without `version`, returns PDF versions and the change log. With `version`, downloads that historical PDF. With `actual=1`, downloads the current PDF directly. All requests require the `X-Api-Key` header. Use `incluirDetalle=1` to include before-and-after snapshots for each change.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "DeCA identifier.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 125
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "description": "Version number to download as PDF.",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 2
          },
          {
            "name": "actual",
            "in": "query",
            "required": false,
            "description": "Use `1` to download the current PDF version directly.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ],
              "default": 0
            }
          },
          {
            "name": "incluirDetalle",
            "in": "query",
            "required": false,
            "description": "Includes previous and new data for each change.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON history or PDF content, depending on the parameters.",
            "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": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and 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": [
          "Multi-stop trips"
        ],
        "operationId": "guardarReparto",
        "summary": "Create or update a multi-shipment DeCA",
        "description": "Use `accion=crear` to create and `accion=actualizar` with `id` for a partial update. Including `envios` replaces the entire previous collection. Without `fechaTransporte`, the document remains pending and no PDF is generated.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accion"
                ],
                "properties": {
                  "accion": {
                    "type": "string",
                    "enum": [
                      "crear",
                      "actualizar"
                    ]
                  },
                  "id": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Required when updating."
                  },
                  "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": "Stable email, order or shipment identifier. Up to 512 UTF-16 units; never truncated. Unique per company together with origenRegistro."
                  },
                  "modoEdicionTransportista": {
                    "type": "string",
                    "enum": [
                      "operativo",
                      "carga"
                    ],
                    "default": "operativo",
                    "description": "`carga` also allows the carrier to edit each line description, quantity, unit and weight."
                  },
                  "diasValidezEnlace": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 30
                  },
                  "envios": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/EnvioReparto"
                    }
                  }
                }
              },
              "examples": {
                "crearReparto": {
                  "summary": "Route with two deliveries",
                  "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": "Update shared details only",
                  "value": {
                    "accion": "actualizar",
                    "id": 125,
                    "matriculaTractora": "7350 LPD"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Multi-stop trip updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepartoResponse"
                }
              }
            }
          },
          "201": {
            "description": "Multi-stop trip created",
            "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": [
          "Multi-stop trips"
        ],
        "operationId": "consultarRepartos",
        "summary": "Retrieve, find or list multi-stop trips",
        "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 to exclude single-shipment documents.",
            "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": "Successful query",
            "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": [
          "ERP master data"
        ],
        "operationId": "consultarEntidades",
        "summary": "Retrieve or list customers and carriers",
        "description": "Without identification parameters, returns a paginated list. Retrieve a specific record using `id` or the `origen` + `idExterno` pair.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Internal entity identifier.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "System that assigned the external reference. Send together with idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Stable ERP record identifier. Send together with origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filter by status. The default returns active and inactive records.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Free-text search in the main fields and external reference.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of items per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "First item of the page.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "rol",
            "in": "query",
            "description": "Filter entities by their role in DeCA.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "cliente",
                "transportista",
                "ambos"
              ],
              "default": "todos"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful query.",
            "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": [
          "ERP master data"
        ],
        "operationId": "guardarEntidad",
        "summary": "Create, update, activate or deactivate an entity",
        "description": "Use `accion=guardar` for idempotent synchronization. If `origenRegistro` + `idExterno` already exists, the record is updated; otherwise it is created. `actualizar`, `activar` and `desactivar` accept `id` or an external reference. No physical deletion is performed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClienteWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Create or update an entity from the 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": "Deactivate by ERP reference",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CLI-00428"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Record updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Record created.",
            "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": [
          "ERP master data"
        ],
        "operationId": "importarEntidades",
        "summary": "Validate or batch-import customers and carriers",
        "description": "Processes 1 to 1,000 records in isolation for the company linked to `X-Api-Key`. Use `accion=validar` first; `accion=importar` processes the entire batch in a transaction and saves no rows if any error exists. Duplicates are identified by ERP reference, tax ID or name within the same company.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClienteImportacionRequest"
              },
              "examples": {
                "validar": {
                  "summary": "Preview before importing",
                  "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": "Confirm a validated batch",
                  "value": {
                    "accion": "importar",
                    "modoDuplicados": "actualizar",
                    "registros": [
                      {
                        "origenRegistro": "ERP_EMPRESA",
                        "idExterno": "CLI-00428",
                        "nombre": "Harinas Leonesas SL",
                        "nif": "B24010101",
                        "esCliente": true
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch validated or imported successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteImportacionResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Subscription expired.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "description": "The batch contains validation errors.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClienteImportacionResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_vehiculos.php": {
      "get": {
        "tags": [
          "ERP master data"
        ],
        "operationId": "consultarVehiculos",
        "summary": "Get or list vehicles",
        "description": "Without identification parameters, returns a paginated list. Retrieve a specific record using `id` or the `origen` + `idExterno` pair.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Internal vehicle identifier.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "System that assigned the external reference. Send together with idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Stable ERP record identifier. Send together with origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filter by status. The default returns active and inactive records.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Free-text search in the main fields and external reference.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of items per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "First item of the page.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful query.",
            "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": [
          "ERP master data"
        ],
        "operationId": "guardarVehiculo",
        "summary": "Create, update, activate or deactivate a vehicle",
        "description": "Use `accion=guardar` for idempotent synchronization. If `origenRegistro` + `idExterno` already exists, the record is updated; otherwise it is created. `actualizar`, `activar` and `desactivar` accept `id` or an external reference. No physical deletion is performed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VehiculoWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Create or update a vehicle from the ERP",
                  "value": {
                    "accion": "guardar",
                    "matricula": "1234 KLM",
                    "tipo": "tractora",
                    "marca": "Volvo",
                    "modelo": "FH 460",
                    "activo": true,
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "VEH-00117"
                  }
                },
                "desactivar": {
                  "summary": "Deactivate by ERP reference",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "VEH-00117"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Record updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VehiculoWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Record created.",
            "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": [
          "ERP master data"
        ],
        "operationId": "consultarConductores",
        "summary": "Get or list drivers",
        "description": "Without identification parameters, returns a paginated list. Retrieve a specific record using `id` or the `origen` + `idExterno` pair.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Internal driver identifier.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "description": "System that assigned the external reference. Send together with idExterno.",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "idExterno",
            "in": "query",
            "description": "Stable ERP record identifier. Send together with origen.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "activo",
            "in": "query",
            "description": "Filter by status. The default returns active and inactive records.",
            "schema": {
              "type": "string",
              "enum": [
                "todos",
                "1",
                "0"
              ],
              "default": "todos"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Free-text search in the main fields and external reference.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of items per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "First item of the page.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful query.",
            "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": [
          "ERP master data"
        ],
        "operationId": "guardarConductor",
        "summary": "Create, update, activate or deactivate a driver",
        "description": "Use `accion=guardar` for idempotent synchronization. If `origenRegistro` + `idExterno` already exists, the record is updated; otherwise it is created. `actualizar`, `activar` and `desactivar` accept `id` or an external reference. No physical deletion is performed.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConductorWriteRequest"
              },
              "examples": {
                "sincronizar": {
                  "summary": "Create or update a driver from the 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": "Deactivate by ERP reference",
                  "value": {
                    "accion": "desactivar",
                    "origenRegistro": "ERP_EMPRESA",
                    "idExterno": "CON-00032"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Record updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConductorWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Record created.",
            "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": [
          "ERP master data"
        ],
        "operationId": "consultarLugares",
        "summary": "Retrieve or list saved places",
        "description": "Optional master data for farms, warehouses and recurring locations. The API key always limits results to its company.",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "origen",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 50
            },
            "description": "System that assigned the external reference; use together with idExterno."
          },
          {
            "name": "idExterno",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Stable ERP reference; use together with 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": "Successful query.",
            "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": [
          "ERP master data"
        ],
        "operationId": "guardarLugar",
        "summary": "Create, update, activate or deactivate a saved place",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LugarWriteRequest"
              },
              "examples": {
                "synchronise": {
                  "summary": "Create or update an ERP farm",
                  "value": {
                    "accion": "guardar",
                    "codigo": "FR-018",
                    "nombre": "Los Prados Farm",
                    "domicilio": "Rural Road 4, Segovia",
                    "esOrigen": true,
                    "esDestino": false,
                    "activo": true,
                    "origenRegistro": "CUSTOMER_ERP",
                    "idExterno": "FARM-018"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Record updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LugarWriteResponse"
                }
              }
            }
          },
          "201": {
            "description": "Record created.",
            "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": [
          "Downloads"
        ],
        "operationId": "createDownloadBatch",
        "summary": "Prepare a ZIP batch of PDFs",
        "description": "Takes a snapshot of the current versions. It immediately returns HTTP 202 and an idLote; the ERP then checks the status without keeping the request open.",
        "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": "Excludes versions that have already been downloaded."
                  }
                },
                "description": "Provide a date range or a list of ids. Maximum 10,000 documents and 512 MB."
              },
              "example": {
                "fechaCampo": "transporte",
                "fechaDesde": "2026-09-01",
                "fechaHasta": "2026-09-30",
                "soloPendientes": true
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DownloadBatch"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "get": {
        "tags": [
          "Downloads"
        ],
        "operationId": "getOrDownloadBatch",
        "summary": "Check or download a batch",
        "description": "accion=estado advances preparation in blocks and returns progress. Repeat until estado=disponible. accion=descargar returns the ZIP and records each downloaded version. The ZIP expires 24 hours after becoming available.",
        "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": "JSON status or ZIP file, depending on accion.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DownloadBatch"
                }
              },
              "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": "The temporary ZIP has expired."
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api_usuario_actual.php": {
      "get": {
        "tags": ["ERP master data"],
        "operationId": "getCurrentApiUser",
        "summary": "Identify a personal API key",
        "description": "Requires only X-User-Api-Key. Returns the authenticated user and company; the general company key is not accepted and no secrets are returned.",
        "security": [{"UserApiKeyAuth": []}],
        "responses": {
          "200": {
            "description": "Identity associated with the personal key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["ok", "idUsuario", "usuario", "idEmpresa", "nombreEmpresa", "nombreComercial"],
                  "properties": {
                    "ok": {"type": "boolean", "enum": [true]},
                    "idUsuario": {"type": "integer"},
                    "usuario": {"type": "string"},
                    "idEmpresa": {"type": "integer"},
                    "nombreEmpresa": {"type": "string", "description": "Company sign-in code."},
                    "nombreComercial": {"type": "string"}
                  }
                },
                "example": {"ok": true, "idUsuario": 12, "usuario": "OPERATOR", "idEmpresa": 3, "nombreEmpresa": "EXAMPLE", "nombreComercial": "Example Company"}
              }
            }
          },
          "401": {"$ref": "#/components/responses/Unauthorized"},
          "403": {"$ref": "#/components/responses/Forbidden"},
          "405": {"description": "Only GET is allowed."},
          "429": {"description": "Too many failed attempts from the same IP. See Retry-After header.", "headers": {"Retry-After": {"schema": {"type": "integer"}}}},
          "500": {"$ref": "#/components/responses/ServerError"}
        }
      }
    },
    "/api_usuarios.php": {
      "get": {
        "tags": [
          "ERP master data"
        ],
        "operationId": "listApiUsers",
        "summary": "List users and personal-key status",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Users without full key values."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "ERP master data"
        ],
        "operationId": "manageApiUsers",
        "summary": "Import users or regenerate/revoke a personal key",
        "description": "Requires X-Api-Key. Complete keys are returned only when generated. Each user may include nombreVisible (optional, max. 120 characters), which is shown on screen only. Omitting it when updating an existing user preserves its value; null or an empty string clears it. New users see only their own DeCAs by default; in companies with isolation enabled, they cannot see other users' catalogs without permission. Omitting activo, accesoTodosDeca or soloPropiosDeca when updating an existing user preserves the current values. The usuario field remains the sign-in code.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "accion": "importar",
                "usuarios": [
                  {
                    "usuario": "operator1",
                    "nombreVisible": "Alicante operator",
                    "clave": "SecureWebPassword",
                    "activo": true,
                    "accesoTodosDeca": true,
                    "soloPropiosDeca": true,
                    "generarApiKey": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Operation completed."
          },
          "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": "32-character key assigned to the company. Treat it as a password and never include it in URLs or diagnostic logs."
      },
      "UserApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-User-Api-Key",
        "description": "Personal key identifying both company and user. Do not send it together with X-Api-Key."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request or incomplete data",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "fechaTransporte debe ser YYYY-MM-DD."
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "Clave API no válida."
            }
          }
        }
      },
      "Forbidden": {
        "description": "API unavailable for the company or subscription expired",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "Suscripción caducada."
            }
          }
        }
      },
      "NotFound": {
        "description": "Record not found for the authenticated company.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "DeCA no encontrado."
            }
          }
        }
      },
      "Conflict": {
        "description": "A record with the same details or external reference already exists.",
        "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": "The operation could not be completed",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "ok": false,
              "error": "No se pudo completar la operación."
            }
          }
        }
      }
    },
    "schemas": {
      "DownloadBatch": {
        "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": "Only returned when estado is disponible. It requires the same X-Api-Key."
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "LineaMercancia": {
        "type": "object",
        "description": "Line of transported goods.",
        "properties": {
          "descripcion": {
            "type": "string",
            "maxLength": 200,
            "description": "Description of the goods."
          },
          "cantidad": {
            "type": "number",
            "minimum": 0,
            "nullable": true,
            "description": "Quantity in the specified unit."
          },
          "unidad": {
            "type": "string",
            "maxLength": 30,
            "nullable": true,
            "description": "Unit of measure: pallets, packages, sacks, m3, etc."
          },
          "pesoKg": {
            "type": "number",
            "minimum": 0,
            "nullable": true,
            "description": "Line weight in kilograms."
          }
        }
      },
      "DecaInputFields": {
        "type": "object",
        "properties": {
          "idCliente": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Entity with the customer role. Send 0 or null in an update to remove the link."
          },
          "idTransportista": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Entity with the carrier role. Send 0 or null in an update to remove the link."
          },
          "cargadorNombre": {
            "type": "string",
            "description": "Contractual consignor name or company name. Required when a transport date is set."
          },
          "cargadorNif": {
            "type": "string",
            "description": "Contractual consignor tax ID. Required when a transport date is set."
          },
          "cargadorDomicilio": {
            "type": "string",
            "description": "Contractual consignor address. Required when a transport date is set."
          },
          "transportistaNombre": {
            "type": "string",
            "description": "If omitted, uses the configured company name."
          },
          "transportistaNif": {
            "type": "string",
            "description": "If omitted, uses the configured company tax ID."
          },
          "origen": {
            "type": "string",
            "maxLength": 512,
            "description": "Place of origin. Required when a transport date is set."
          },
          "destino": {
            "type": "string",
            "maxLength": 512,
            "description": "Destination. Required when a transport date is set."
          },
          "fechaTransporte": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Trip date in YYYY-MM-DD format. Omit it or send an empty string to leave the trip unscheduled."
          },
          "matriculaTractora": {
            "type": "string",
            "nullable": true,
            "description": "Main vehicle registration, if known. Send an empty string or null in an update to clear it."
          },
          "matriculaRemolque": {
            "type": "string",
            "nullable": true,
            "description": "Trailer registration, if applicable. Send an empty string in an update to clear it."
          },
          "observaciones": {
            "type": "string",
            "nullable": true
          },
          "numAlbaran": {
            "type": "string",
            "nullable": true,
            "description": "Delivery-note number. If supplied during creation, the document is marked as having a delivery note."
          },
          "anulado": {
            "type": "boolean",
            "description": "Optional status, mainly used in updates."
          },
          "terminado": {
            "type": "boolean",
            "description": "Optional status, mainly used in updates."
          },
          "albaranado": {
            "type": "boolean",
            "description": "Optional status, mainly used in updates."
          },
          "origenRegistro": {
            "type": "string",
            "nullable": true,
            "description": "Stable source-system code, for example `ERP_CLIENTE`."
          },
          "idExterno": {
            "type": "string",
            "nullable": true,
            "description": "Stable email, order or shipment identifier. Up to 512 UTF-16 units; never truncated. Unique per company together with origenRegistro.",
            "maxLength": 512
          },
          "modoEdicionTransportista": {
            "type": "string",
            "enum": [
              "operativo",
              "carga"
            ],
            "default": "operativo",
            "description": "Private-link permissions. `operativo`: date and registrations. `carga`: also goods description, quantity, unit and weight. Does not allow changes to companies, tax IDs, routes or administrative statuses."
          },
          "diasValidezEnlace": {
            "type": "integer",
            "minimum": 1,
            "maximum": 90,
            "default": 30,
            "description": "Validity in days when a new link is needed. Retrieving an active link does not change its token or expiry."
          },
          "lineas": {
            "type": "array",
            "description": "Trip goods. With a date set, at least one line must have a description and at least one must specify `pesoKg` or `cantidad` + `unidad`. Sending this property in an update replaces all previous lines.",
            "items": {
              "$ref": "#/components/schemas/LineaMercancia"
            }
          },
          "mercancia": {
            "type": "string",
            "deprecated": true,
            "description": "Compatibility field for creating a single line. Use `lineas` in new integrations."
          },
          "pesoKg": {
            "type": "number",
            "minimum": 0,
            "deprecated": true,
            "description": "Compatibility field associated with `mercancia`."
          },
          "otraMagnitud": {
            "type": "string",
            "deprecated": true,
            "description": "Compatibility field associated with `mercancia`."
          },
          "idConductor": {
            "type": "integer",
            "minimum": 0,
            "nullable": true,
            "description": "Short form for assigning one driver. Use conductores to assign two."
          },
          "notaConductorDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Trip-specific note for the driver assigned in short form."
          },
          "mostrarNotaConductorDeca": {
            "type": "boolean",
            "description": "Shows the short-form driver note in the PDF."
          },
          "conductores": {
            "type": "array",
            "minItems": 0,
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/ConductorDeca"
            },
            "description": "Optional. Replaces all assignments. Omit on update to keep current drivers; [] clears them. Supports idConductor (legacy) or name/contact data for a one-off driver. Does not modify master records."
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "description": "Includes driver names and authorised notes in the PDF. On creation it is inherited from the customer when omitted. It never includes an ID number, telephone or email."
          },
          "idLugarOrigen": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Saved origin place belonging to the same company. When supplied, the API copies its name and address to the trip."
          },
          "idLugarDestino": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Saved destination place belonging to the same company. When supplied, the API copies its name and address to the trip."
          }
        }
      },
      "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": "`idDeca` identifier to update."
              }
            }
          }
        ]
      },
      "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": "ERP order, dispatch or delivery."
          },
          "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": "Saved origin place belonging to the same company. When supplied, the API copies its name and address to the trip."
          },
          "idLugarDestino": {
            "type": "integer",
            "minimum": 1,
            "nullable": true,
            "description": "Saved destination place belonging to the same company. When supplied, the API copies its name and address to the trip."
          }
        },
        "description": "Origin and destination may be entered manually or resolved with idLugarOrigen and idLugarDestino. When a transport date is set, every shipment must have valid text or identifiers for both."
      },
      "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",
              "carga"
            ],
            "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": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and 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": "Technical document-URL token. The integration should retain `idDeca`, `urlEdicion` and its external reference."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Legacy field: stable document URL. May be unavailable until a PDF exists. Use `urlDocumento` and `urlEdicion` in new integrations."
          },
          "urlDocumento": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Public view of the current DeCA. Null until a PDF version exists."
          },
          "urlDescargaPdf": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Authenticated endpoint for downloading the current PDF with `X-Api-Key`."
          },
          "pdfDisponible": {
            "type": "boolean"
          },
          "urlEdicion": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Private link to include in the order sent to the carrier. Does not require an API key."
          },
          "modoEdicionTransportista": {
            "type": "string",
            "enum": [
              "operativo",
              "carga"
            ],
            "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": "Null while the trip has no date or PDF."
          },
          "pdf": {
            "type": "boolean",
            "description": "Indicates whether this operation generated a PDF version."
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and URLs."
          },
          "incluirConductorPdf": {
            "type": "boolean"
          },
          "conductores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConductorDecaRespuesta"
            }
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the consignor signature area."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the consignee signature area."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the carrier or driver signature area."
          }
        }
      },
      "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",
              "carga"
            ],
            "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": "Current tractor registration. Null until assigned."
          },
          "matriculaRemolque": {
            "type": "string",
            "maxLength": 15,
            "nullable": true,
            "description": "Current trailer registration. Null if not applicable or not yet assigned."
          },
          "estado": {
            "$ref": "#/components/schemas/EstadoDeca"
          },
          "origenRegistro": {
            "type": "string",
            "nullable": true
          },
          "idExterno": {
            "type": "string",
            "nullable": true,
            "maxLength": 512,
            "description": "Stable email, order or shipment identifier. Up to 512 UTF-16 units; never truncated. Unique per company together with origenRegistro."
          },
          "lineas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LineaMercancia"
            }
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and URLs."
          },
          "incluirConductorPdf": {
            "type": "boolean"
          },
          "conductores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConductorDecaRespuesta"
            }
          },
          "envios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EnvioReparto"
            },
            "description": "Structured routes and goods. Includes saved-place identifiers when they were used."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the consignor signature area."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the consignee signature area."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "description": "Indicates whether the PDF includes the carrier or driver signature area."
          }
        }
      },
      "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": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and 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": "Stable email, order or shipment identifier. Up to 512 UTF-16 units; never truncated. Unique per company together with origenRegistro."
          },
          "estado": {
            "$ref": "#/components/schemas/EstadoDeca"
          },
          "numeroEmpresa": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "readOnly": true,
            "description": "Sequential and immutable DeCA number within a company. Read-only. It does not replace the global ID used in requests and URLs."
          }
        }
      },
      "DecaListadoResponse": {
        "type": "object",
        "required": [
          "ok",
          "total",
          "limit",
          "offset",
          "fechaCampo",
          "items"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "total": {
            "type": "integer",
            "description": "Total records matching the filter."
          },
          "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": "Readable message describing the error cause."
          }
        }
      },
      "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": "Preference copied to each new DeCA for the customer."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignor signature area to the footer of new DeCAs."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignee signature area to the footer of new DeCAs."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a carrier or driver signature area to the footer of new DeCAs."
          }
        }
      },
      "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` is recommended for ERP synchronization because it creates or updates by external reference."
          },
          "id": {
            "type": "integer",
            "minimum": 1,
            "description": "Internal ID, required if no external reference is used."
          },
          "nombre": {
            "type": "string",
            "maxLength": 150
          },
          "nif": {
            "type": "string",
            "maxLength": 20
          },
          "domicilio": {
            "type": "string",
            "maxLength": 200,
            "nullable": true
          },
          "esCliente": {
            "type": "boolean",
            "default": true,
            "description": "Allows selecting the entity as the contractual consignor."
          },
          "esTransportista": {
            "type": "boolean",
            "default": false,
            "description": "Allows selecting the entity as the actual carrier."
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with origenRegistro."
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Preference copied to each new DeCA for the customer."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignor signature area to the footer of new DeCAs."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignee signature area to the footer of new DeCAs."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a carrier or driver signature area to the footer of new DeCAs."
          }
        }
      },
      "VehiculoWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar",
            "description": "`guardar` is recommended for ERP synchronization because it creates or updates by external reference."
          },
          "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": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with origenRegistro."
          }
        }
      },
      "ConductorWriteRequest": {
        "type": "object",
        "required": [
          "accion"
        ],
        "properties": {
          "accion": {
            "type": "string",
            "enum": [
              "crear",
              "actualizar",
              "guardar",
              "activar",
              "desactivar"
            ],
            "default": "guardar",
            "description": "`guardar` is recommended for ERP synchronization because it creates or updates by external reference."
          },
          "id": {
            "type": "integer",
            "minimum": 1
          },
          "nombre": {
            "type": "string",
            "maxLength": 150
          },
          "telefono": {
            "type": "string",
            "description": "The supplied text is preserved exactly, without adding a country code or removing spaces, signs or hyphens. Maximum 20 characters.",
            "maxLength": 20
          },
          "email": {
            "type": "string",
            "maxLength": 500,
            "nullable": true,
            "description": "One or more valid email addresses separated by semicolons. Up to 10 are allowed."
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "If true, sends automatic notifications when the pending DeCA is created and when it becomes complete. Requires an email address."
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with origenRegistro."
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Operational note proposed for the driver's new DeCA documents."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "default": false,
            "description": "Proposes showing notaDeca next to the name in new DeCA documents."
          }
        }
      },
      "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": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with origenRegistro."
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          },
          "incluirConductorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Preference copied to each new DeCA for the customer."
          },
          "firmaExpedidorPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignor signature area to the footer of new DeCAs."
          },
          "firmaDestinatarioPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a consignee signature area to the footer of new DeCAs."
          },
          "firmaTransportistaPdf": {
            "type": "boolean",
            "default": false,
            "description": "Adds a carrier or driver signature area to the footer of new DeCAs."
          }
        }
      },
      "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": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with 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": "The supplied text is preserved exactly, without adding a country code or removing spaces, signs or hyphens. Maximum 20 characters.",
            "maxLength": 20
          },
          "email": {
            "type": "string",
            "nullable": true,
            "description": "Email addresses separated by semicolons."
          },
          "notificarEmail": {
            "type": "boolean"
          },
          "activo": {
            "type": "boolean"
          },
          "origenRegistro": {
            "type": "string",
            "maxLength": 50,
            "nullable": true,
            "description": "Stable source-system code. Send together with idExterno."
          },
          "idExterno": {
            "type": "string",
            "maxLength": 80,
            "nullable": true,
            "description": "Stable ERP identifier. Send together with origenRegistro."
          },
          "fechaAlta": {
            "type": "string",
            "format": "date-time"
          },
          "fechaModificacion": {
            "type": "string",
            "format": "date-time"
          },
          "notaDeca": {
            "type": "string",
            "maxLength": 300,
            "nullable": true,
            "description": "Operational note proposed for the driver's new DeCA documents."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "default": false,
            "description": "Proposes showing notaDeca next to the name in new DeCA documents."
          }
        }
      },
      "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 if created; false if updated."
          },
          "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 if created; false if updated."
          },
          "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 if created; false if updated."
          },
          "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": "Trip-specific operational note. Do not include an ID number, telephone, email or unnecessary private data."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "description": "Shows notaDeca next to the driver name when incluirConductorPdf is true."
          },
          "nombre": {
            "type": "string",
            "maxLength": 100,
            "description": "Required for a one-off driver without idConductor."
          },
          "telefono": {
            "type": "string",
            "nullable": true,
            "maxLength": 20,
            "description": "The supplied text is preserved exactly, without adding a country code or removing spaces, signs or hyphens. Maximum 20 characters."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "maxLength": 500
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "For this document. A valid email is required when true."
          }
        },
        "description": "Up to two drivers per document. Send idConductor to copy an existing profile, or nombre for a one-off driver. Contact overrides belong only to this DeCA; profile records are not modified."
      },
      "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": "The place must be enabled for at least origin or destination. Use guardar with origenRegistro and idExterno for idempotent synchronisation."
      },
      "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": "Trip-specific operational note. Do not include an ID number, telephone, email or unnecessary private data."
          },
          "mostrarNotaDeca": {
            "type": "boolean",
            "description": "Shows notaDeca next to the driver name when incluirConductorPdf is true."
          },
          "nombre": {
            "type": "string",
            "maxLength": 100,
            "description": "Required for a one-off driver without idConductor."
          },
          "telefono": {
            "type": "string",
            "nullable": true,
            "maxLength": 20,
            "description": "The supplied text is preserved exactly, without adding a country code or removing spaces, signs or hyphens. Maximum 20 characters."
          },
          "email": {
            "type": "string",
            "nullable": true,
            "maxLength": 500
          },
          "notificarEmail": {
            "type": "boolean",
            "description": "For this document. A valid email is required when true."
          },
          "orden": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2
          }
        },
        "description": "Driver snapshot saved in the document. idConductor is null for one-off drivers."
      }
    }
  }
}
