API de DeCA
Dos maneras de dejar un documento electrónico de control administrativo en el repositorio de deca.infonetconsultores.com. Las dos acaban igual: un PDF con su URL de descarga directa y su QR, tal como pide la Resolución de 5 de junio de 2026. Elige según lo que ya tengas hecho.
| Base URL | https://deca.infonetconsultores.com |
| Protocolo | HTTPS (TLS 1.2 o superior) · JSON UTF-8 |
| Auth | Token Bearer en la cabecera Authorization, uno por cliente |
| Modo A | POST /subir · tú generas el PDF con el QR y nos lo subes |
| Modo C | POST /deca · nos mandas los datos y te devolvemos PDF, QR y URL |
| Gestión | /administrador · /maestros · /conductores · contraseña del administrador, maestros y conductores de la empresa, con su mismo token |
| Clientes | GET /alta · POST /alta · consulta o da de alta un cliente y obtiene su token (aplicaciones de Infonet) |
| Municipios | GET /municipios · lista pública de localidades del INE para origen_localidad y destino_localidad, sin token |
Cuál de las dos usar
Si tu programa ya imprime un albarán o un documento de control y puedes pintarle un código QR, usa el modo A: sigues con tu plantilla y solo añades el QR y una llamada para subir el fichero. Es lo que hacen Arigest, Agrocom, GAP, Gesthorm, Facturacom y Recodat.
Si prefieres no tocar tu generador de PDF, o no tienes uno, usa el modo C: nos mandas los datos del documento y te devolvemos el PDF terminado, el QR como imagen y la URL. Es una sola llamada y no hay que preocuparse del formato del documento, del tamaño, de los metadatos ni del QR.
| Modo A · subes tu PDF | Modo C · nos mandas los datos | |
|---|---|---|
| Quién hace el PDF | Tu programa | Nosotros |
| Quién pone el QR | Tu programa. La URL es predecible: /documentos/<slug>/<nombre>, así que puedes generar el QR antes de subir | Nosotros, dentro del PDF y como PNG aparte |
| Qué envías | Nombre del cliente, nombre del fichero y el PDF en base64 | Los datos del artículo 6 en JSON |
| Qué recibes | Confirmación con carpeta, fichero y bytes | URL, PDF en base64, QR en base64, identificador |
| Nombre del fichero | Lo pones tú. Tiene que ser largo y aleatorio para que la URL no se pueda adivinar | Lo ponemos nosotros: DECA_<32 hex>.pdf |
| Queda registrado en la plataforma web | No | Sí, aparece en el listado de /app/ del cliente |
| Modificar un documento | Subes un fichero nuevo, con otro nombre, y entregas el nuevo PDF | Vuelves a llamar con el mismo numero_documento: se sustituye el anterior |
| Responsabilidad de que el PDF cumpla | Tuya: nativo (no escaneado), menos de 5 MB, QR con la URL exacta | Nuestra |
Alta y credenciales
Cada empresa se identifica por su cliente aplicación: un nombre corto que decide la carpeta donde quedan sus documentos. Es el mismo texto que tu aplicación manda en el campo cliente de /subir, y se normaliza a minúsculas y guiones: HORMIGONES EJEMPLO pasa a ser hormigones-ejemplo. Una empresa solo puede tener un cliente aplicación y dos empresas no pueden compartirlo.
El alta se hace de dos maneras, y las dos llevan al mismo sitio:
- Por API, desde las aplicaciones de Infonet, con
/alta: mandas el cliente aplicación y recibes su token del modo C. Si ya existe, te devuelve el que hay; nunca se crean duplicados. - En nuestro panel, cuando la empresa va a entrar además en la plataforma web: ahí se completan el nombre, el contacto, la cuota y los usuarios.
El token del modo C es siempre el mismo: /alta te lo devuelve igual cada vez que lo pidas. Solo cambia si lo renovamos desde el panel, por ejemplo si se ha filtrado. El token del modo A (el de tu aplicación para /subir) es otro distinto.
En el modo A necesitas el cliente aplicación para construir la URL del QR. En el modo C no hace falta, la URL viene en la respuesta.
Repositorio, URL y QR
Todo documento acaba en https://deca.infonetconsultores.com/documentos/<slug>/<fichero>.pdf. Esa dirección es la que va dentro del QR y la que quien inspecciona descarga en un control. Cumple lo que exige la Resolución de 5 de junio de 2026:
- Empieza por
https://y el servidor sirve TLS 1.2 o superior. - Descarga directa: al abrirla se obtiene el PDF, sin página intermedia, sin usuario ni contraseña, sin botones.
- No caduca. La norma permite desactivarla a los siete días del servicio, pero no lo exige, y así queda cubierto el año de conservación sin más.
- No hay listado de carpetas: quien no tenga la URL exacta no puede ver qué hay.
En el modo C el QR contiene exactamente esa URL y nada más. En el modo A el QR lo pintas tú: pon la URL completa, sin parámetros ni texto añadido.
Lo que no hace falta: registrar el dominio, subir nada a ninguna plataforma del Ministerio, certificar la aplicación ni firmar el documento. La Resolución de 2026 quitó el registro previo que pedía la de 2023, y la FAQ del Ministerio lo dice con todas las letras.
Autenticación
Las dos llamadas se autentican igual: cabecera Authorization con el token del cliente. Los endpoints de gestión usan el mismo token que /deca. /alta usa en cambio el token maestro de las aplicaciones de Infonet, que no pertenece a ningún cliente; guárdalo solo en el servidor de la aplicación. Los tokens no caducan; si sospechas que uno se ha filtrado, llámanos y lo cambiamos en el momento. Nunca lo pongas en una URL ni en un formulario web visible.
Authorization: Bearer <TU_TOKEN>
| Situación | Respuesta |
|---|---|
| Cabecera ausente o mal formada | 401 + WWW-Authenticate: Bearer |
| Token presente pero incorrecto | 403 en /subir, 401 en /deca |
Modo A: POST /subir
Crea la carpeta del cliente si no existe y guarda el PDF con el nombre indicado. Nunca queda un PDF a medias: si algo falla, no se guarda nada.
Cabeceras
| Cabecera | Tipo | Valor | |
|---|---|---|---|
| Authorization | string | obligatoria | Bearer <token> |
| Content-Type | string | recomendada | application/json — si se omite o es distinta, el cuerpo se lee como formulario ($_POST) |
Cuerpo de la petición
Se acepta application/json (recomendado) o application/x-www-form-urlencoded / multipart/form-data con los mismos nombres de campo.
| Campo | Tipo | Descripción | |
|---|---|---|---|
| cliente | string | obligatorio | El cliente aplicación: el mismo que usas en /alta y el que tiene la empresa en nuestro panel. Mándalo siempre igual, porque de él depende la carpeta y, por tanto, que los documentos de la aplicación y los de la web queden juntos. Se convierte en el nombre de la carpeta: se quitan acentos, se pasa a minúsculas y se sustituye todo lo no alfanumérico por guiones. Máximo 100 caracteres tras el saneado."Transportes Pérez, S.L." → carpeta transportes-perez-s-l |
| nombre_fichero | string | obligatorio | Nombre con el que se guardará el PDF. Se filtran los caracteres a [A-Za-z0-9._-] y se fuerza la extensión .pdf. Máximo 150 caracteres. |
| pdf_base64 | string | obligatorio | Contenido del PDF codificado en Base64. Se admiten saltos de línea y espacios (se eliminan) y el formato Data URI data:application/pdf;base64,…. Máximo 20 MB ya decodificado. |
Esquema
{
"cliente": "Transportes Perez SL",
"nombre_fichero": "ALB-2026-0001.pdf",
"pdf_base64": "JVBERi0xLjQKMSAwIG9iajw8L1R5cGUv..."
}
Ejemplos de petición
# El PDF se codifica al vuelo y se inserta en el JSON curl -X POST https://deca.infonetconsultores.com/subir \ -H "Authorization: Bearer TU_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"cliente\":\"Transportes Perez SL\", \"nombre_fichero\":\"ALB-2026-0001.pdf\", \"pdf_base64\":\"$(base64 -w0 albaran.pdf)\"}"
Respuesta correcta
https://deca.infonetconsultores.com/documentos/<cliente>/<fichero>.{
"ok": true,
"cliente": "transportes-perez-sl",
"fichero": "ALB-2026-0001.pdf",
"ruta": "documentos/transportes-perez-sl/ALB-2026-0001.pdf",
"bytes": 152340
}
| Campo | Tipo | Descripción |
|---|---|---|
| ok | boolean | Siempre true en la respuesta 201. |
| cliente | string | Slug realmente usado como carpeta, ya saneado. |
| fichero | string | Nombre final tras el saneado y el forzado de extensión. |
| ruta | string | Ruta del PDF dentro del repositorio. La URL de descarga es la base más esta ruta. |
| bytes | integer | Tamaño del PDF decodificado, en bytes. |
Errores
Todos los errores devuelven {"ok": false, "error": "<mensaje>"} con el código HTTP correspondiente.
{
"ok": false,
"error": "El contenido decodificado no es un PDF."
}
Catálogo completo
error los distingue."Falta el parámetro \"cliente\"." · "Falta el parámetro \"nombre_fichero\"." · "Falta el parámetro \"pdf_base64\"."
"Data URI mal formado en \"pdf_base64\"."
"El campo \"pdf_base64\" no contiene base64 válido."
"El nombre de cliente no contiene caracteres válidos." · "El nombre de fichero no contiene caracteres válidos."
"Ruta de destino no permitida."
Authorization, o no sigue el formato Bearer <token>. Se devuelve WWW-Authenticate: Bearer.Allow: POST.%PDF-. Evita que se suban ejecutables o scripts renombrados."No se pudo crear el directorio base de subidas." · "No se pudo crear la carpeta del cliente."
"No se pudo escribir el fichero en disco." · "No se pudo mover el fichero a su destino final."
Saneado de nombres
Ningún dato del cliente llega en crudo al sistema de ficheros. Estas son las transformaciones exactas:
Carpeta de cliente
| Entrada | Carpeta resultante |
|---|---|
| Transportes Pérez, S.L. | transportes-perez-s-l |
| LOGÍSTICA DEL SUR | logistica-del-sur |
| !!! | 400 — no quedan caracteres válidos |
Nombre de fichero
| Entrada | Fichero resultante |
|---|---|
| ALB-2026-0001.pdf | ALB-2026-0001.pdf sin cambios |
| albarán nº5.pdf | albar_n_5.pdf |
| factura | factura.pdf extensión forzada |
Límites y validación
| Límite | Valor |
|---|---|
| Tamaño máximo del PDF | 20 MB una vez decodificado |
| Cuerpo máximo de la petición | 32 MB (el Base64 ocupa un 33 % más que el PDF) |
| Sobrescritura | No. Un nombre repetido devuelve 409 |
| Longitud del nombre de cliente | 100 caracteres tras el saneado |
| Longitud del nombre de fichero | 150 caracteres, extensión .pdf incluida |
Orden de validación
El endpoint corta en el primer fallo, en este orden:
1. Método POST ................... 405 2. Cabecera Authorization ........ 401 3. Token válido .................. 403 4. JSON parseable ................ 400 5. Los tres campos presentes ..... 400 6. Base64 decodificable .......... 400 7. Tamaño <= 20 MB ............... 413 8. Empieza por %PDF- ............. 415 9. Nombres saneables ............. 400 10. No existe ya el fichero ....... 409 11. Guardado ...................... 500 si falla 201 Created
Conversor PDF → Base64
El fichero no sale de tu navegador: la conversión es local con FileReader. Útil para preparar el cuerpo JSON de Postman.
Probar el endpoint del modo A
Lanza una petición real contra /subir con tu token. El token no se guarda en ningún sitio: vive solo en este campo mientras la pestaña esté abierta.
Modo C: POST /deca
Mandas los datos del documento en JSON. Comprobamos que estén todos los del artículo 6 de la Orden FOM/2861/2012, generamos el PDF con el QR, lo guardamos en la carpeta del cliente, lo apuntamos en la base de datos y te devolvemos la URL, el PDF y el QR en la misma respuesta. Todo o nada: si algo falla no queda ningún fichero a medias.
Cabeceras
| Cabecera | Tipo | Valor | |
|---|---|---|---|
| Authorization | string | obligatoria | Bearer <token del cliente> |
| Content-Type | string | obligatoria | application/json. Sin ella, el servidor responde 403 antes de procesar la petición. |
Cuerpo
{
"cargador": { "nombre": "Hormigones Ejemplo SL", "nif": "B12345678", "domicilio": "Pol. Ind. Norte 4, 21007 Huelva" },
"transportista": { "nombre": "Transportes Pérez SL", "nif": "B87654321" },
"fecha_transporte": "2026-10-06",
"matricula_tractor": "1234ABC",
"matricula_remolque": "R1234BCD",
"autorizacion_especial": null,
"numero_documento": "ALB-2026-0001",
"nif_vehiculo": "12345678Z",
"envios": [
{
"origen": "Planta Norte",
"origen_localidad": "Huelva (Huelva)",
"destino": "Obra Avda. Andalucía 12",
"destino_localidad": "Aljaraque (Huelva)",
"mercancia": "Hormigón HA-25",
"peso": "24.000 kg"
}
],
"observaciones": ""
}
| Campo | Tipo | Qué es y cómo lo tratamos | |
|---|---|---|---|
| cargador.nombre | string | obligatorio | Nombre o razón social del cargador contractual: quien contrata directamente al transportista efectivo. Puede ser la planta, una agencia, una cooperativa o incluso otro transportista que subcontrata. |
| cargador.nif | string | obligatorio | Entre 8 y 9 caracteres alfanuméricos. Se pasa a mayúsculas y se quitan espacios, guiones y puntos. No comprobamos la letra de control. |
| cargador.domicilio | string | obligatorio | Domicilio del cargador contractual. La Orden lo pide solo para el cargador, no para el transportista. |
| transportista.nombre | string | obligatorio* | Nombre o razón social del transportista efectivo: el titular de la autorización con la que se hace el transporte. Si es un autónomo subcontratado, él. * No se manda en un borrador ( transportista_pendiente). |
| transportista.nif | string | obligatorio* | Igual que el del cargador. |
| fecha_transporte | string | obligatorio | Formato AAAA-MM-DD. En el PDF se imprime como DD/MM/AAAA. |
| matricula_tractor | string | obligatorio* | Matrícula del vehículo. Se pasa a mayúsculas y se quitan espacios y guiones: 1234 abc se guarda como 1234ABC.* No se manda en un borrador, ni tampoco matricula_remolque ni autorizacion_especial. |
| matricula_remolque | string | opcional | Solo en conjuntos articulados. Si va, el PDF rotula las dos casillas como "Matrícula tractor" y "Matrícula remolque"; si no, una sola casilla "Matrícula". |
| autorizacion_especial | string | null | opcional | Identificación de la autorización especial de circulación, solo cuando el vehículo la necesite. Si no va, la casilla no aparece en el PDF. |
| numero_documento | string | opcional | Tu número de albarán o referencia interna, hasta 40 caracteres. Se imprime en el PDF y se muestra en la plataforma web. No forma parte del artículo 6; es para que localices el documento. Si ya hay un DeCA activo con el mismo número en el mismo año, la llamada lo sustituye: ver Modificar un DeCA. |
| motivo | string | opcional | Solo cuenta cuando la llamada sustituye a un documento anterior. Por qué se cambia, hasta 200 caracteres ("cambio de remolque"). Si no lo mandas se escribe "Cambiado desde API". |
| nif_vehiculo | string | opcional | NIF/Vehículo del conductor: su DNI o NIE ("12345678Z") o la matrícula de su vehículo ("1234ABC"), según cómo lo tenga puesto su acceso: un solo campo, se comprueba como DNI/NIE o como matrícula. El documento queda a su nombre, como si lo hubiera hecho él en la plataforma web: le aparece en su lista (que solo enseña los de hoy y de ayer) y puede modificarlo. Debe ser el NIF/Vehículo de un acceso activo de la empresa (se pone en /conductores o en «Usuarios») y, si es conductor, el transportista.nif del documento tiene que ser el suyo. Si no, 422 y no se crea nada. Sin este campo, todo funciona como siempre. |
| transportista_pendiente | boolean | opcional | Con true se crea un borrador: sin transportista ni vehículo y sin PDF, pero ya con su URL y su QR. Quien lea el QR por primera vez escribe el NIF del transportista y la matrícula, y entonces se genera el PDF en esa misma URL. Sin este campo (o con false), todo como siempre. |
| envios | array | al menos uno | Lista de envíos (cargas o descargas), con los campos de las filas siguientes. Varios envíos en un mismo DeCA solo si comparten cargador y transportista; el orden no implica secuencia. |
| envios[].origen | string | obligatorio* | Lugar de carga en texto libre: "Planta Norte", "Cantera El Pino, km 4".* Pasa a ser opcional si mandas origen_localidad. |
| envios[].origen_localidad | string | opcional | Municipio de carga, exactamente como aparece en GET /municipios: "Huelva (Huelva)". Se comprueba contra la lista oficial del INE y se imprime a continuación del lugar: "Planta Norte - Huelva (Huelva)". Si no está en la lista, error 422. Detalle en Localidades. |
| envios[].destino | string | obligatorio* | Lugar de descarga en texto libre: "Obra Avda. Andalucía 12".* Pasa a ser opcional si mandas destino_localidad. |
| envios[].destino_localidad | string | opcional | Municipio de descarga, igual que origen_localidad: "Aljaraque (Huelva)". |
| envios[].mercancia | string | obligatorio | Naturaleza de la mercancía: "Hormigón HA-25", "Zahorra artificial". |
| envios[].peso | string | obligatorio | Texto libre porque a veces no se puede pesar y la Orden admite otra magnitud ("24.000 kg", "8 m³"). Si empieza por un número, se escribe en formato español con separador de miles: "24000 kg" se guarda e imprime como "24.000 kg" y "1234.5 t" como "1.234,5 t". |
| observaciones | string | opcional | Reservas o indicaciones de cualquiera de las partes. Si la llamada sustituye a otro documento, la nota «Sustituye al documento… Motivo: …» la añadimos nosotros: no la escribas aquí (usa motivo). |
Localidades de origen y destino · GET /municipios
El origen y el destino se pueden mandar de dos formas. Las dos son válidas; la segunda es la recomendada porque garantiza que la localidad está bien escrita y es la misma que usa la plataforma web.
- Solo texto libre en
origenydestino, como hasta ahora. Se imprime tal cual, sin comprobar nada:"Planta Norte, Huelva". - Con localidad: además (o en lugar) del texto, mandas
origen_localidady/odestino_localidadcon un municipio de la lista oficial del INE. Lo comprobamos y en el documento sale «lugar - Localidad (Provincia)».
Se puede usar en un campo y no en el otro, y cada envío va por su cuenta. Así queda en el PDF:
| Mandas | Sale en el documento |
|---|---|
"origen": "Planta Norte" | Planta Norte |
"origen": "Planta Norte", "origen_localidad": "Huelva (Huelva)" | Planta Norte - Huelva (Huelva) |
"origen_localidad": "Huelva (Huelva)" (sin origen o vacío) | Huelva (Huelva) |
"origen_localidad": "huelva (HUELVA)" | Huelva (Huelva) · se acepta sin respetar mayúsculas ni tildes y se escribe en su forma oficial |
"origen": "Planta Norte - Huelva (Huelva)", "origen_localidad": "Huelva (Huelva)" | Planta Norte - Huelva (Huelva) · si el texto ya termina en esa localidad, no se repite |
"origen_localidad": "Huelva" | Error 422: falta la provincia entre paréntesis. Tiene que ser una entrada de la lista |
Ni origen ni origen_localidad | Error 422: envios[0].origen: obligatorio |
Plataforma web: allí la localidad es siempre obligatoria. Un DeCA que mandaste solo con texto es válido tal cual, pero si alguien lo modifica desde la web tendrá que elegir las localidades de la lista (la web propone la que reconoce en el texto). Si lo modificas por API, sigue siendo opcional.
GET /municipios
La lista de localidades válidas: los 8.132 municipios de España según el INE, cada uno como "Localidad (Provincia)". Es pública: no lleva token. Úsala para rellenar un desplegable o un buscador en tu programa y manda en origen_localidad / destino_localidad el texto exacto que devuelve.
| Petición | Devuelve |
|---|---|
GET /municipios | La lista completa (unos 210 KB). Cambia como mucho una vez al año: guárdala en tu programa y no la pidas en cada envío. |
GET /municipios?q=alcala | Los que contienen ese texto, sin importar mayúsculas ni tildes; primero los que empiezan por él. Hasta 50. |
GET /municipios?q=alcala&limite=200 | Igual, hasta el número indicado (máximo 500). |
curl "https://deca.infonetconsultores.com/municipios?q=aljaraque" { "ok": true, "total": 1, "municipios": [ "Aljaraque (Huelva)" ] }
Si no hay coincidencias, "total": 0 y "municipios": [] (sigue siendo 200). Cualquier método que no sea GET devuelve 405. La respuesta se puede cachear una semana (Cache-Control y ETag).
¿Y la plataforma web? En la web la localidad es obligatoria y se elige de esta misma lista. Por API es opcional para no romper integraciones que ya mandan texto libre; si empiezas una integración nueva, manda siempre la localidad.
Ejemplo
curl -X POST https://deca.infonetconsultores.com/deca \ -H "Authorization: Bearer TU_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @deca.json
# PowerShell $cuerpo = Get-Content deca.json -Raw Invoke-RestMethod -Method Post -Uri "https://deca.infonetconsultores.com/deca" ` -Headers @{ Authorization = "Bearer TU_TOKEN" } ` -ContentType "application/json; charset=utf-8" -Body $cuerpo
// PHP $ch = curl_init('https://deca.infonetconsultores.com/deca'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer TU_TOKEN', 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($datos, JSON_UNESCAPED_UNICODE), ]); $r = json_decode(curl_exec($ch), true); file_put_contents('deca.pdf', base64_decode($r['pdf_base64']));
Respuesta 201 (o 200)
{
"ok": true,
"accion": "creado",
"id": 123,
"estado": "activo",
"sustituye_a": null,
"fichero": "DECA_3f9a1c0d8b2e4f6a9c1d3e5f7a9b0c2e.pdf",
"url": "https://deca.infonetconsultores.com/documentos/hormigones-ejemplo-sl/DECA_3f9a1c0d8b2e4f6a9c1d3e5f7a9b0c2e.pdf",
"creado": "2026-10-06T07:30:00+02:00",
"conductor": null,
"pdf_base64": "JVBERi0xLjcK…",
"qr_png_base64": "iVBORw0KGgo…"
}
| Campo | Tipo | Descripción |
|---|---|---|
| ok | boolean | Siempre true en un 201. |
| accion | string | "creado": documento nuevo. "sustituido": documento nuevo que sustituye al activo con el mismo número (aunque los datos sean idénticos). |
| id | integer | Identificador interno del documento. Sirve para localizarlo en la plataforma web y para consultarlo con GET /deca/{id}. |
| estado | string | "activo": DeCA con su PDF. "pendiente": borrador, aún sin transportista ni PDF. |
| sustituye_a | integer | null | Con "sustituido", el id del documento anterior, que queda marcado como sustituido. Si no, null. |
| fichero | string | DECA_ seguido de 32 caracteres hexadecimales aleatorios. |
| url | string | La dirección de descarga directa. Es lo que contiene el QR. Es lo que hay que hacer llegar a quien conduce si no le mandas el PDF. |
| creado | string | Fecha y hora de creación, ISO 8601 con zona horaria. Coincide con los metadatos del PDF. |
| conductor | string | null | Con nif_vehiculo, el acceso a cuyo nombre queda el documento ("hormigonesejemplo.luis"). Si no, null. |
| pdf_base64 | string | null | El PDF completo, unos 12 KB. Descodifícalo y guárdalo, imprímelo o envíalo. En un borrador, null: el PDF sale cuando se completa (recógelo en la url o con GET /deca/{id}). |
| qr_png_base64 | string | El mismo QR que va en el PDF, como PNG, por si quieres pegarlo en tu propio albarán o mandarlo suelto. |
Errores
Todos los errores devuelven JSON con "ok": false y un "error" legible. El 422 añade además la lista "errores" con un texto por campo.
| HTTP | Cuándo | Cuerpo |
|---|---|---|
| 405 | Cualquier método que no sea POST ni GET | {"ok":false,"error":"Método no permitido. Use POST (alta) o GET /deca/{id} (consulta)."} y cabecera Allow: GET, POST |
| 401 | Sin cabecera Authorization | {"ok":false,"error":"Falta la cabecera Authorization: Bearer <token>."} |
| 401 | Token que no corresponde a ningún cliente activo | {"ok":false,"error":"Token no válido."} |
| 403 | Token correcto pero la cuota del cliente ha caducado | {"ok":false,"error":"La cuota del servicio DeCA ha caducado. Contacta con Infonet Consultores (959 54 07 12)."} |
| 403 | POST sin Content-Type ni cuerpo | Página HTML del servidor, no JSON. Manda siempre Content-Type: application/json. |
| 400 | El cuerpo no es un objeto JSON válido (JSON roto, texto suelto, codificación que no es UTF-8) | {"ok":false,"error":"El cuerpo debe ser un objeto JSON válido."} |
| 422 | Faltan datos o tienen formato incorrecto | {"ok":false,"error":"Datos incompletos o inválidos.","errores":[…]} |
| 409 | Otra llamada estaba sustituyendo el mismo número de documento a la vez y no se pudo resolver tras varios intentos | {"ok":false,"error":"Otra petición está modificando este mismo número de documento. Vuelve a intentarlo."} |
| 500 | Fallo al escribir el PDF o en la base de datos | {"ok":false,"error":"No se pudo generar el documento."}. Si se repite, llámanos. |
Mensajes posibles en errores (422)
Cada texto empieza por el campo al que se refiere, con la misma ruta que en el JSON. Puedes mostrarlos tal cual al usuario o mapearlos a tus propios campos.
| Mensaje | Motivo |
|---|---|
cargador.nombre: obligatorio | El campo falta o está vacío tras recortar espacios. |
cargador.nif: obligatorio | |
cargador.domicilio: obligatorio | |
transportista.nombre: obligatorio | |
transportista.nif: obligatorio | |
fecha_transporte: obligatorio | |
matricula_tractor: obligatorio | |
cargador.nif: formato inválido (8-9 caracteres alfanuméricos) | Tras normalizar, no quedan entre 8 y 9 letras o dígitos. |
transportista.nif: formato inválido (8-9 caracteres alfanuméricos) | |
fecha_transporte: formato AAAA-MM-DD | No cumple el formato o no es una fecha real (30 de febrero). |
matricula_tractor: caracteres no válidos | Tras normalizar quedan menos de 2 o más de 12 caracteres, o hay algo que no es letra o dígito. |
matricula_remolque: caracteres no válidos | |
envios: se requiere al menos un envío | envios falta, no es un array o está vacío. |
envios[0]: debe ser un objeto | Un elemento de envios no es un objeto. El índice empieza en 0. |
envios[0].origen: obligatorioenvios[0].destino: obligatorioenvios[0].mercancia: obligatorioenvios[0].peso: obligatorio | Falta ese dato en el envío indicado. origen y destino no lo dan si viene su _localidad. |
envios[0].origen_localidad: no es una localidad de la lista (GET /municipios)envios[0].destino_localidad: no es una localidad de la lista (GET /municipios) | El texto no coincide con ninguna entrada de GET /municipios, ni siquiera sin mayúsculas ni tildes. Suele ser que falta la provincia: "Huelva" en vez de "Huelva (Huelva)". |
nif_vehiculo: NIF/Vehículo no válido (DNI o NIE con su letra correcta, o la matrícula del vehículo) | No es un DNI (8 cifras y letra) ni un NIE (X, Y o Z, 7 cifras y letra) con la letra correcta, ni una matrícula (de 4 a 12 letras y números). |
nif_vehiculo: no hay ningún acceso activo de la empresa con el NIF/Vehículo 12345678Z | Ese NIF/Vehículo no está puesto a ningún acceso de la empresa, o el acceso está desactivado. Ponlo con POST /conductores ("nif_vehiculo") o en «Usuarios». |
nif_vehiculo: el conductor 12345678Z es de Transportes Pérez SL (B87654321), no del transportista B11111111 | El conductor solo puede hacer DeCA de su transportista, igual que en la plataforma web. |
transportista_pendiente: true o false | El campo viene con otro valor ("si", 1…). |
transportista.nif: no se envía con transportista_pendiente (lo pone quien lee el QR) | En un borrador sobran transportista, matricula_tractor, matricula_remolque y autorizacion_especial: hay un mensaje así por cada uno que venga relleno. |
nif_vehiculo: el conductor 12345678Z ya tiene transportista; un borrador (transportista_pendiente) no puede ir a su nombre | Un conductor siempre trabaja con su transportista: si ya sabes quién conduce, manda el DeCA completo. |
{
"ok": false,
"error": "Datos incompletos o inválidos.",
"errores": [
"cargador.domicilio: obligatorio",
"fecha_transporte: formato AAAA-MM-DD",
"envios[1].peso: obligatorio"
]
}
Modificar un DeCA: mismo número de documento
No hay endpoint de edición ni de borrado. Para modificar, vuelve a llamar a POST /deca con el mismo numero_documento y el DeCA completo ya corregido (todos los campos, no solo lo que cambia). Es lo mismo que hace el botón «Modificar» de la plataforma web, y cumple la segunda opción de la Resolución para cambios una vez empezado el servicio:
- Se genera un documento nuevo, con nueva URL y nuevo QR (
"accion": "sustituido"). - El anterior queda marcado como sustituido y se sigue pudiendo descargar. No se borra nunca: la Orden pide conservarlos al menos un año.
- Al principio de las observaciones del nuevo se escribe la nota, que también sale en el PDF:
Sustituye al documento DECA_….pdf. Motivo: …. El motivo es el campomotivo, oCambiado desde APIsi no lo mandas. No la añadas tú; si la reenvías copiada del documento anterior, se quita y no se repite. - Haz llegar el nuevo PDF o la nueva URL a quien conduce. El QR antiguo ya no es el válido. Lo que no vale es corregir a mano una copia impresa.
// 1.ª llamada → 201, "accion": "creado", "id": 123 { "numero_documento": "ALB-2026-0001", "matricula_remolque": "R1234BCD", … } // Cambia el remolque: mismo número, todo el DeCA → 201, "accion": "sustituido", "id": 124, "sustituye_a": 123 { "numero_documento": "ALB-2026-0001", "matricula_remolque": "R5678FGH", "motivo": "cambio de remolque", … }
| Cuándo se considera el mismo documento | |
|---|---|
Mismo cliente (token), mismo numero_documento y mismo año de fecha_transporte, y el anterior está activo | Se sustituye |
Número escrito exactamente igual. ALB-1 y alb-1 son números distintos | Documento nuevo |
Sin numero_documento (o vacío) | Siempre documento nuevo, como hasta ahora |
Mismo número pero fecha_transporte de otro año (numeraciones que empiezan de cero cada año) | Documento nuevo; el del otro año no se toca |
| Mismo número y exactamente los mismos datos que el activo | Se sustituye igual: cada llamada genera una versión nueva (otra URL, otro PDF) |
| El activo con ese número se hizo en la plataforma web | Se sustituye igual: es el mismo transporte |
Codificación: manda el JSON en UTF-8. Si llega en otra codificación (por ejemplo Windows-1252 desde un programa antiguo), la reconvertimos y no falla, pero mejor evitarlo.
Reintentos: cada llamada genera un documento. Con número de documento, un reintento tras un timeout sustituye al anterior y solo queda uno activo (el último). Sin número, cada llamada crea un documento nuevo; guarda la respuesta antes de reintentar.
Borrador sin transportista: lo completa quien lee el QR
Para cuando aún no sabes qué transportista ni qué camión harán el viaje. Manda el DeCA sin transportista, matricula_tractor, matricula_remolque ni autorizacion_especial y con "transportista_pendiente": true:
- Se crea un borrador (
"estado": "pendiente") con suurly su QR definitivos, pero sin PDF ("pdf_base64": null). Imprime o manda el QR ya: no cambia. - La primera persona que abre la URL (o lee el QR) escribe el NIF completo del transportista y la matrícula. Sin desplegables: tienen que coincidir con los transportistas y vehículos de la empresa (/maestros). Si la empresa tiene activados los datos escritos a mano, lo que no esté se puede escribir solo para ese DeCA; si no, no se puede cerrar. Con remolques separados, también el remolque.
- Al confirmar se genera el PDF en esa misma URL y el DeCA queda cerrado (
"estado": "activo"): desde entonces el QR abre el PDF y funciona como cualquier otro DeCA (mismo número = sustituir, etc.). - El borrador reserva su número: otra llamada con el mismo
numero_documentolo sustituye, como a un activo. Un borrador sustituido queda muerto para siempre: su QR dice que ya no vale. - Si pasa la
fecha_transportesin completarse, caduca ("estado": "caducado") y libera el número. La oficina también puede anularlo desde la plataforma web. - Para saber si ya se cerró y recoger el PDF:
GET /deca/{id}, o descarga laurl.
{
"cargador": { "nombre": "Hormigones Ejemplo SL", "nif": "B12345678", "domicilio": "Pol. Ind. Norte 4, 21007 Huelva" },
"fecha_transporte": "2026-10-06",
"numero_documento": "ALB-2026-0002",
"envios": [{ "origen_localidad": "Huelva (Huelva)", "destino_localidad": "Aljaraque (Huelva)", "mercancia": "Hormigón HA-25", "peso": "24.000 kg" }],
"transportista_pendiente": true
}
// → 201, "estado": "pendiente", "pdf_base64": null, "url" y "qr_png_base64" ya válidos
GET /deca/{id}: estado y PDF de un DeCA
Con el mismo Authorization: Bearer. También vale GET /deca?id=123. Solo ves los documentos de tu empresa (si no, 404).
curl https://deca.infonetconsultores.com/deca/123 -H "Authorization: Bearer TU_TOKEN" { "ok": true, "id": 123, "estado": "activo", "numero_documento": "ALB-2026-0002", "fecha_transporte": "2026-10-06", "sustituye_a": null, "sustituido_por": null, "fichero": "DECA_3f9a….pdf", "url": "https://deca.infonetconsultores.com/documentos/…/DECA_3f9a….pdf", "creado": "2026-10-05T18:02:00+02:00", "cerrado": "2026-10-06T06:41:00+02:00", "transportista": { "nombre": "Transportes Pérez SL", "nif": "B87654321" }, "matricula_tractor": "1234ABC", "matricula_remolque": "R1234BCD", "pdf_base64": "JVBERi0xLjcK…", "qr_png_base64": "iVBORw0KGgo…" }
| estado | Qué significa | pdf_base64 |
|---|---|---|
activo | DeCA válido. Si venía de un borrador, cerrado dice cuándo se completó. | El PDF |
pendiente | Borrador esperando a que alguien lea el QR y ponga transportista y matrícula. transportista es null. | null |
sustituido | Hay otro más nuevo con el mismo número: su id en sustituido_por. | El PDF, si llegó a tenerlo |
caducado | Borrador cuyo día de transporte pasó sin completarse. | null |
anulado | Borrador anulado por la oficina. | null |
Gestión: POST /administrador
Los endpoints de gestión se llaman con el token de la empresa, el mismo de POST /deca (el que devuelve /alta), en la cabecera Authorization: Bearer <token>. Todo lo que hacen queda dentro de esa empresa: no se ve ni se toca nada de otra. Responden JSON con "ok": true o "ok": false y "error".
Pone contraseña nueva al acceso web <cliente>.administrador que crea /alta. Sin cuerpo se genera una aleatoria de 16 caracteres; con {"password": "..."} se pone esa (de 8 a 72 caracteres, sin espacios al principio ni al final). Si el acceso estaba desactivado, se reactiva; si no existe, se crea como acceso de oficina (HTTP 201). La contraseña anterior deja de valer en el momento.
# Aleatoria curl -X POST https://deca.infonetconsultores.com/administrador \ -H "Authorization: Bearer TOKEN_EMPRESA" # Elegida curl -X POST https://deca.infonetconsultores.com/administrador \ -H "Authorization: Bearer TOKEN_EMPRESA" \ -H "Content-Type: application/json" \ -d '{"password":"MiClaveSegura1"}'
{
"ok": true,
"creado": false,
"usuario": "hormigonesejemplo.administrador",
"password": "Xk7mPq2RtW9vHn4c",
"acceso": "https://deca.infonetconsultores.com/app/"
}
200 si el acceso ya existía, 201 si se ha creado. 409 si la empresa no tiene matriz de usuarios (empresas antiguas dadas de alta a mano): no tiene <cliente>.administrador; pídenoslo.
Gestión: /maestros
Los maestros son las listas de la plataforma web con las que se rellena un DeCA: cargadores, transportistas (empresas de transporte), vehículos y mercancías. Por API se consultan y se mantienen igual que desde la web. POST /deca no los necesita: sigue recibiendo los datos en texto.
| tipo | Clave (única en la empresa) | Campos |
|---|---|---|
| cargadores | nif | nombre, nif, domicilio — todos obligatorios |
| transportistas | nif | nombre (razón social), nif — obligatorios. Opcional vehiculos: lista de sus vehículos, ver abajo |
| vehiculos | matricula | matricula (obligatoria), transportista_id o transportista_nif (obligatorio, el transportista debe existir), matricula_remolque, autorizacion (hasta 60) |
| mercancias | nombre | nombre — obligatorio |
| remolques | matricula | Solo en empresas con remolques separados. matricula (obligatoria), transportista_id o transportista_nif (obligatorio), autorizacion (autorización especial, hasta 60) |
El tipo va en la URL (o en el JSON en POST y PUT). NIF y matrículas se normalizan como en el modo C: "b-12.345 678" se guarda "B12345678", "1234 abc" se guarda "1234ABC".
- GET sin
idniclavedevuelve la lista de activos; con&todos=1, también los desactivados. En vehículos,&transportista_id=5filtra por transportista. - POST no crea duplicados: si ya hay uno con la misma clave devuelve ese con HTTP 200 y
"creado": false, sin modificarlo (para cambiarlo,PUT). Si estaba desactivado, lo reactiva ("reactivado": true). Si lo crea, HTTP 201. - PUT cambia solo los campos que mandes; el resto queda como estaba. Con
"activo": true|falselo activa o desactiva. - DELETE no borra: desactiva. Deja de salir en los formularios, pero los documentos ya hechos con él no cambian. Un
POSTcon la misma clave lo reactiva.
Transportista con sus vehículos
En POST y PUT de tipo=transportistas (y en el transportista de /conductores) puedes mandar "vehiculos": una lista de objetos con matricula (obligatoria), matricula_remolque y autorizacion. Para cada uno:
- Matrícula nueva: se crea como vehículo de ese transportista.
- Matrícula que ya existe: pasa a ser de ese transportista (aunque fuera de otro), se actualizan los campos que mandes (los que no, se quedan) y se reactiva si estaba desactivada.
- Los vehículos que ya tenía el transportista y no vienen en la lista no se tocan: para quitar uno,
DELETE /maestros?tipo=vehiculos&id=.... - Va todo junto: si un vehículo no vale (error 422 con
"vehiculos[1]: ..."), no se guarda nada, ni el transportista ni los demás vehículos.
Esto vale también cuando el transportista ya existe (HTTP 200): no se cambian sus datos, pero sí se añaden o actualizan los vehículos. La respuesta trae "vehiculos_creados" (cuántos eran nuevos) y el transportista con todos sus vehículos activos en maestro.vehiculos. Un transportista siempre sale con su lista vehiculos, también en GET.
# Alta de una empresa de transporte con sus vehículos curl -X POST "https://deca.infonetconsultores.com/maestros?tipo=transportistas" \ -H "Authorization: Bearer TOKEN_EMPRESA" \ -H "Content-Type: application/json" \ -d '{"nombre":"Transportes Pérez SL","nif":"B87654321", "vehiculos":[{"matricula":"1234ABC","matricula_remolque":"R1234BCD"},{"matricula":"5678DEF"}]}' # Un vehículo suelto curl -X POST "https://deca.infonetconsultores.com/maestros?tipo=vehiculos" \ -H "Authorization: Bearer TOKEN_EMPRESA" \ -H "Content-Type: application/json" \ -d '{"transportista_nif":"B87654321","matricula":"1234ABC","matricula_remolque":"R1234BCD"}' # ¿Existe este NIF? curl "https://deca.infonetconsultores.com/maestros?tipo=transportistas&clave=B87654321" \ -H "Authorization: Bearer TOKEN_EMPRESA"
Respuesta de un elemento (POST, PUT, DELETE y GET con id o clave):
{
"ok": true,
"tipo": "transportistas",
"creado": true, // solo en POST
"reactivado": false, // solo en POST
"vehiculos_creados": 2, // solo si mandas "vehiculos"
"maestro": {
"id": 5,
"nombre": "Transportes Pérez SL",
"nif": "B87654321",
"activo": true,
"creado": "2026-10-05T11:40:00+02:00",
"vehiculos": [ // solo en transportistas
{"id": 8, "matricula": "1234ABC", "matricula_remolque": "R1234BCD", "autorizacion": ""},
{"id": 9, "matricula": "5678DEF", "matricula_remolque": "", "autorizacion": ""}
]
}
}
La lista (GET sin id) devuelve {"ok": true, "tipo": "...", "total": 3, "maestros": [ ... ]} con elementos de la misma forma.
Remolques separados
Por defecto cada vehículo lleva su remolque y su autorización: todo lo de arriba. Para empresas cuyos tractores y remolques se van combinando, Infonet puede activar los remolques separados. Sin esa opción no cambia nada; con ella:
- Existe
tipo=remolques, con el mismoGET/POST/PUT/DELETEque los demás maestros (&transportista_id=5filtra la lista). Cada remolque es de un transportista y lleva suautorizacionespecial. - Un transportista admite
"remolques": [{"matricula": "R1234BCD", "autorizacion": "..."}], igual que"vehiculos"(también en/conductores). La respuesta trae"remolques_creados"y el transportista sale convehiculosyremolques. - Los vehículos son solo el tractor: salen como
{"id", "matricula"}, y si mandasmatricula_remolqueoautorizacionen un vehículo se rechaza con 422 ("matricula_remolque: esta empresa tiene los remolques separados…") en vez de perderse sin avisar. - En la plataforma web, el DeCA se hace eligiendo vehículo y, aparte, remolque (o «Sin remolque»).
POST /decaes igual en los dos casos:matricula_remolqueyautorizacion_especialsiguen yendo en texto.
En una empresa sin la opción, tipo=remolques o "remolques" en un transportista devuelven 422 explicando que hay que pedirla a Infonet.
# Empresa con remolques separados: tractores y remolques por separado curl -X POST "https://deca.infonetconsultores.com/maestros?tipo=transportistas" \ -H "Authorization: Bearer TOKEN_EMPRESA" \ -H "Content-Type: application/json" \ -d '{"nombre":"Transportes Pérez SL","nif":"B87654321", "vehiculos":[{"matricula":"1234ABC"},{"matricula":"5678DEF"}], "remolques":[{"matricula":"R1234BCD","autorizacion":"AE-2026-15"},{"matricula":"R5678FGH"}]}'
Gestión: GET · POST /conductores
?usuario=luis o ?nif_vehiculo=12345678Z para uno)Un conductor es un acceso a la plataforma web ligado a una empresa de transporte: solo puede usar ese transportista y sus vehículos y solo ve los documentos que crea él. Con una llamada se crea el acceso y, si hace falta, la empresa de transporte.
| Campo | Tipo | Qué es | |
|---|---|---|---|
| nombre | string | obligatorio | Nombre descriptivo de la persona: "Luis Pérez". |
| usuario | string | obligatorio | Lo que va tras el punto: con "luis" el acceso es <cliente>.luis. Letras, números, punto, guion o arroba. |
| password | string | obligatoria | La contraseña que elijas, de 8 a 72 caracteres, sin espacios al principio ni al final. No se devuelve. |
| nif_vehiculo | string | opcional | NIF/Vehículo: el DNI o NIE del conductor, con su letra correcta ("12345678Z"), o la matrícula de su vehículo ("1234ABC") si los DeCA van al camión. Un solo campo: se comprueba como DNI/NIE o como matrícula. Único dentro de la empresa. Permite crear DeCA a su nombre con nif_vehiculo. Si no mandas el campo no se cambia; con "" se quita. |
| transportista.nif | string | obligatorio | NIF de la empresa de transporte. Si ya está en los maestros de la empresa, el conductor se enlaza a ese transportista (y se reactiva si estaba desactivado). |
| transportista.nombre | string | si no existe | Razón social. Solo se usa si el NIF no existe y hay que crear el transportista; si existe, no se cambia. |
| transportista.vehiculos | array | opcional | Vehículos del transportista: [{"matricula": "1234ABC", "matricula_remolque": "R1234BCD", "autorizacion": ""}]. Las mismas reglas que en /maestros: los nuevos se crean, los existentes pasan a este transportista y se actualizan. |
| transportista.remolques | array | opcional | Solo con remolques separados: [{"matricula": "R1234BCD", "autorizacion": ""}], con las mismas reglas. |
curl -X POST https://deca.infonetconsultores.com/conductores \ -H "Authorization: Bearer TOKEN_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "nombre": "Luis Pérez", "usuario": "luis", "password": "LuisClave2026", "nif_vehiculo": "12345678Z", "transportista": { "nombre": "Transportes Pérez SL", "nif": "B87654321", "vehiculos": [{"matricula": "1234ABC", "matricula_remolque": "R1234BCD"}] } }'
{
"ok": true,
"creado": true,
"transportista_creado": false,
"vehiculos_creados": 1,
"id": 31,
"usuario": "hormigonesejemplo.luis",
"nombre": "Luis Pérez",
"nif_vehiculo": "12345678Z",
"activo": true,
"ultimo_acceso": null,
"transportista": {
"id": 5, "nombre": "Transportes Pérez SL", "nif": "B87654321", "activo": true,
"vehiculos": [{"id": 8, "matricula": "1234ABC", "matricula_remolque": "R1234BCD", "autorizacion": ""}]
},
"acceso": "https://deca.infonetconsultores.com/app/"
}
- 201: conductor nuevo. 200: el usuario ya era conductor de la empresa; se le ponen el nombre, la contraseña y el transportista enviados, y se reactiva si estaba desactivado. Sirve, por tanto, para cambiarle la contraseña o pasarlo a otra empresa de transporte.
- 409: el usuario es un acceso de oficina (por ejemplo
administrador): no se convierte en conductor. Elige otro usuario. - Si algo falla no se guarda nada a medias: ni el transportista, ni sus vehículos, ni el acceso.
GET /conductoresdevuelve{"ok": true, "total": 2, "conductores": [ ... ]}con elementos como el de arriba (sincreadoniacceso).GET /conductores?usuario=luisoGET /conductores?nif_vehiculo=12345678Zdevuelve{"ok": true, "conductor": { ... }}o 404.
Errores de gestión
| HTTP | Cuándo |
|---|---|
| 401 | Falta el token o no es de ninguna empresa activa. |
| 403 | La cuota de la empresa ha caducado. |
| 400 | El cuerpo no es JSON válido. |
| 404 | El maestro o el conductor no existe en la empresa. |
| 409 | /administrador: empresa sin matriz. /conductores: el usuario es de oficina o ya lo usa otra empresa. |
| 422 | Datos que faltan o no valen. El cuerpo lleva "errores" con un texto por problema: ["password: La contraseña debe tener entre 8 y 72 caracteres.", "transportista.nif: obligatorio, 8 o 9 caracteres alfanuméricos"]. En maestros, también tipo desconocido. |
| 405 | Método no admitido por ese endpoint (la cabecera Allow dice cuáles). |
Clientes: GET · POST /alta
Para las aplicaciones de Infonet. Con el cliente aplicación averiguas si la empresa ya está dada de alta y obtienes su token del modo C, o la das de alta en el momento. Nunca se crean duplicados: un POST con un cliente aplicación que ya existe no crea otro, devuelve el existente. Por eso puedes llamar a POST /alta siempre que tu aplicación necesite el token, sin comprobar antes.
El token devuelto es siempre el mismo para cada empresa. Guárdalo y úsalo en POST /deca; si lo pierdes, vuelve a pedirlo. Solo cambia si lo renovamos desde nuestro panel.
Empresas dadas de alta antes del 2 de octubre de 2026. De ellas solo guardábamos el resumen del token, no el token, así que no lo podemos devolver. La primera vez que pidas por /alta una de esas empresas se genera un token nuevo, te lo devolvemos, y el que tuvieras guardado deja de valer en ese momento. Sustitúyelo por el devuelto en cuanto lo recibas. A partir de ahí es siempre el mismo.
Una empresa nueva se crea con un año de cuota, con el cliente aplicación como nombre provisional y con un acceso a la plataforma web: el usuario <cliente>.administrador (por ejemplo hormigonesejemplo.administrador) con una contraseña aleatoria. Usuario y contraseña vienen en la respuesta 201 y solo en esa: guárdalos o pásaselos a la empresa en ese momento. Su nombre, contacto y más accesos se completan en el panel.
Cabeceras
| Cabecera | Tipo | Valor | |
|---|---|---|---|
| Authorization | string | obligatoria | Bearer <token maestro>. No es el token de ningún cliente. |
| Content-Type | string | en POST | application/json |
Parámetros
| Campo | Tipo | Qué es | |
|---|---|---|---|
| cliente | string | obligatorio | El cliente aplicación, el mismo que mandas en /subir. En GET va en la URL; en POST, en el JSON. Se normaliza igual que la carpeta: "HORMIGONES EJEMPLO", "hormigones ejemplo" y "hormigones-ejemplo" son el mismo cliente. |
| nombre | string | opcional, solo POST | Nombre de la empresa si se crea ahora. Si no va, se usa el cliente aplicación hasta que lo completemos en el panel. No cambia el nombre de una empresa que ya existía. |
Ejemplos
# ¿Existe? Si existe, su token curl https://deca.infonetconsultores.com/alta?cliente=hormigonesejemplo \ -H "Authorization: Bearer TOKEN_MAESTRO" # Alta si no existe (o el existente si ya está) curl -X POST https://deca.infonetconsultores.com/alta \ -H "Authorization: Bearer TOKEN_MAESTRO" \ -H "Content-Type: application/json" \ -d '{"cliente":"hormigonesejemplo"}'
Respuesta
{
"ok": true,
"existe": true,
"creado": false,
"id": 12,
"cliente": "hormigonesejemplo",
"nombre": "Hormigones Ejemplo SL",
"token": "3f9a1c0d8b2e4f6a9c1d3e5f7a9b0c2e…",
"caducidad": "2027-10-06"
}
Si el POST la acaba de crear (HTTP 201), además:
{
"ok": true,
"existe": true,
"creado": true,
…
"usuario": "hormigonesejemplo.administrador",
"password": "Xk7mPq2RtW9vHn4c",
"acceso": "https://deca.infonetconsultores.com/app/"
}
| Campo | Tipo | Descripción |
|---|---|---|
| existe | boolean | true en toda respuesta correcta: la empresa existe (o se acaba de crear). |
| creado | boolean | true si este POST la ha creado (HTTP 201); false si ya existía (HTTP 200). |
| id | integer | Identificador interno de la empresa. |
| cliente | string | Cliente aplicación ya normalizado: el nombre de la carpeta. También se devuelve como slug por compatibilidad. |
| nombre | string | Nombre de la empresa. |
| token | string | Token del modo C, 64 caracteres hexadecimales. Siempre el mismo para la empresa. |
| caducidad | string | null | Fecha hasta la que tiene cuota, AAAA-MM-DD. Pasada esa fecha, POST /deca responde 403. |
| usuario | string | solo en 201 Usuario de la plataforma web: <cliente>.administrador, solo letras y números delante del punto (hasta 20). Si otra empresa ya usa ese prefijo, se numera: hormigonesejemplo2.administrador. |
| password | string | solo en 201 Contraseña de ese usuario, 16 caracteres aleatorios. No se guarda en claro: no se vuelve a devolver. Si se pierde, la renovamos desde el panel. |
| acceso | string | solo en 201 Dirección de entrada a la plataforma web. |
Errores
| HTTP | Cuándo |
|---|---|
| 404 | GET de un cliente aplicación que no existe. El cuerpo lleva "existe": false. Con POST no hay 404: se crea. |
| 401 | Falta el token maestro o no es correcto. |
| 403 | La empresa existe pero está desactivada. |
| 400 | En POST, el cuerpo no es JSON válido. |
| 422 | Falta cliente o queda vacío tras normalizar. |
| 405 | Método distinto de GET o POST. |
| 503 | El alta por API está deshabilitada en el servidor. |
Compatibilidad: un POST con solo {"nombre": "..."}, como en la primera versión, sigue funcionando: el nombre hace de cliente aplicación.
Reintentos: si el POST de alta se corta (timeout) y lo repites, el segundo responde 200 con el token pero ya sin usuario ni password. Con ese token, POST /administrador le pone una contraseña nueva.