Para qué sirve
La API está pensada para empresas de transporte y cargadores que ya gestionan sus pedidos o expediciones en un ERP o TMS y quieren que el DeCA se genere solo, sin volver a teclear datos.
1. Tu ERP / TMS
Envía el pedido o expedición por HTTPS (JSON, Bearer + Idempotency-Key).
2. API DeCA
Valida los datos obligatorios y genera el DeCA.
3. Recibes
La referencia, el PDF con QR y la URL pública de verificación.
¿Necesitas explicárselo a tu empresa? En la página de la API DeCA tienes lo que hace, para quién es y su precio, sin detalles técnicos.
El acceso a la API es un complemento de pago: API Lite con Professional (39,95 €/mes + IVA) o API Advanced con Business (49,95 €/mes + IVA) para integraciones ERP/TMS. Los DeCA creados por la API cuentan en el mismo cupo mensual del plan que los creados desde el panel.
Primeros pasos
- Activa el complemento API desde Plan y facturación (API Lite con el plan Professional; API Advanced con el plan Business). Si tienes dudas, escríbenos a integraciones@praetoriaabogados.es.
- Abre la pestaña Integraciones: en cuanto el complemento está activo, los Administradores de la empresa la tienen en el menú de su panel. Es el centro de integración: allí creas, rotas y revocas tus claves (hasta 2 activas a la vez, todas con el mismo cupo y límites de la empresa), compruebas la conexión, pruebas expediciones en el simulador sin consumir cupo, configuras webhooks y descargas el kit. La clave completa solo se muestra una vez, al crearla.
- Prueba la conexión con
GET /api/v1/me. - Valida un DeCA con
POST /api/v1/decas/validate: no crea nada ni consume cupo. - Crea tu primer DeCA con
POST /api/v1/decasy guarda la URL de verificación.
curl https://decaprofesional.es/api/v1/me \
-H "Authorization: Bearer $DECA_API_KEY"Autenticación
Cada petición lleva la clave de la integración en la cabecera Authorization. Solo HTTPS; no envíes nunca la clave en la URL ni la incluyas en código que se ejecute en el navegador.
Authorization: Bearer fvd_live_<id-de-la-clave>_<secreto>La empresa siempre es la de la credencial: ningún campo de la petición (NIF, identificadores) cambia de empresa. Si pierdes una clave no se puede recuperar: pide una nueva o su rotación. Todo lo que tu credencial no puede ver responde 404.
API Lite y API Advanced
API Lite (plan Professional + 39,95 €/mes + IVA): validar, crear, consultar, descargar el PDF y corregir o anular los DeCA de tu integración; hasta 100 DeCA por API al mes dentro del cupo del plan, 1 clave y 20 peticiones por minuto. Cualquier otra ruta responde 403 api_advanced_required, y la creación número 101 del mes, 429 api_lite_limit_reached. Contrato solo con sus rutas: openapi-lite.json.
API Advanced (plan Business + 49,95 €/mes + IVA): todas las rutas de esta página — webhooks firmados, lotes, sincronización de Datos habituales, órdenes de carga, borradores, solicitudes de datos a terceros y envío automático por email (autoDispatch), con el cupo del plan Business.
# 1) Valida sin crear nada
curl -X POST https://decaprofesional.es/api/v1/decas/validate -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -H "Idempotency-Key: val-001" -d @expedicion.json
# 2) Crea el DeCA
curl -X POST https://decaprofesional.es/api/v1/decas -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -H "Idempotency-Key: exp-001" -d @expedicion.json
# 3) Descarga el PDF
curl https://decaprofesional.es/api/v1/decas/$ID/pdf -H "Authorization: Bearer $KEY" -o deca.pdfcurl -X POST https://decaprofesional.es/api/v1/decas -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -H "Idempotency-Key: exp-002" -d '{
...datos del DeCA...,
"autoDispatch": { "recipients": [
{ "role": "driver", "email": "conductor@tuempresa.es", "name": "Conductor" },
{ "role": "shipper", "email": "trafico@cargador.es" }
] }
}'
# Respuesta: "autoDispatch": { "recipients": [{ "role": "driver", "email": "c***@tuempresa.es", "status": "sent" }, ...] }
# "sent" = aceptado por el servidor de correo (no confirma entrega ni lectura). Un reintento con la misma
# Idempotency-Key devuelve "status": "replayed" y no envía nada más. Máximo 3 destinatarios, sin CC.Endpoints
/api/v1/meLite y AdvancedComprueba la credencial: integración, empresa, permisos, límites y uso del mes.
El primer endpoint que debes llamar para verificar la conexión.
/api/v1/decas/validatedeca:createLite y AdvancedValida un DeCA sin crearlo: mismas reglas que la creación.
No crea ningún DeCA, no genera PDF y no consume el cupo del plan.
/api/v1/decasdeca:createLite y AdvancedIdempotency-Key obligatoriaCrea un DeCA y devuelve la URL de verificación, la referencia y el PDF.
Responde 201 (o 200 si es un reintento con la misma Idempotency-Key). Con completionRequest (o draft: true) crea un borrador y responde 202: ver «Completar un DeCA por un tercero».
/api/v1/decasdeca:readSolo AdvancedLista los DeCA, del más reciente al más antiguo, con paginación por cursor.
Filtros: limit (1–100, por defecto 25), cursor, externalId, groupageRef (referencia del grupaje, G-…), status (active | annulled), createdFrom, createdTo (DD-MM-AAAA, días en hora de Madrid; createdTo incluye todo ese día). Todas las fechas de la API van en DD-MM-AAAA y las horas en hora de Madrid.
/api/v1/decas/{id}deca:readLite y AdvancedEl DeCA completo: estado, periodo del servicio, URL de verificación, PDF y datos.
/api/v1/decas/{id}/statusdeca:readLite y AdvancedEstado ligero (versión, disponibilidad, URL de verificación) para consultas periódicas.
/api/v1/decas/{id}/versionsdeca:readSolo AdvancedHistorial de versiones: motivo del cambio, origen (api / user) y URL y PDF de cada una.
/api/v1/decas/{id}/pdfdeca:readLite y AdvancedDescarga el PDF (versión vigente o ?version=N).
Cabeceras X-Pdf-Sha256 (huella del PDF) y X-Deca-Status (active | annulled).
/api/v1/decas/{id}/correctionsdeca:correctLite y AdvancedIdempotency-Key obligatoriaCorrige un DeCA: crea una nueva versión con nueva URL, QR y PDF.
Responde 201 con la nueva versión (200 si es un reintento con la misma Idempotency-Key). Solo DeCA creados por la misma integración; las versiones anteriores se conservan.
/api/v1/decas/{id}/vehiclesdeca:readSolo AdvancedVehículos del transporte: el inicial y cada cambio registrado, con el actual marcado.
/api/v1/decas/{id}/vehicle-changesdeca:correctSolo AdvancedIdempotency-Key obligatoriaRegistra un cambio de vehículo (tractora y, si cambia, remolque) durante el transporte.
Es una corrección: nueva versión con nueva URL, QR y PDF, que no consume DeCA del plan. La fecha (DD-MM-AAAA) debe estar dentro del transporte y posterior al cambio anterior. Sin trailerPlate se mantiene el remolque anterior. Responde 201 (200 si es un reintento con la misma Idempotency-Key).
/api/v1/decas/{id}/annulmentdeca:annulLite y AdvancedAnula un DeCA. Es definitivo; repetir la llamada devuelve 200 sin cambios.
Solo DeCA creados por la misma integración.
/api/v1/decas/{id}/completion-requestdeca:createSolo AdvancedIdempotency-Key obligatoriaPide a un tercero, por email, los datos que faltan en un borrador.
Responde 201 (200 si es un reintento con la misma Idempotency-Key). Solo borradores de la misma integración.
/api/v1/decas/{id}/completion-request/resenddeca:createSolo AdvancedIdempotency-Key obligatoriaReenvía la solicitud con un enlace nuevo (el anterior deja de funcionar).
Responde 201 (200 si es un reintento). Máximo 5 reenvíos por borrador y hora.
/api/v1/decas/batchdeca:createSolo AdvancedIdempotency-Key obligatoriaCrea hasta 50 DeCA en una sola llamada (lote).
Cuerpo { items: [ …mismo formato que POST /decas… ] }. Responde 202 con el lote ya validado: cada elemento queda pending o failed con sus detalles (un error no afecta a los demás). La creación sigue en segundo plano; consulta GET /api/v1/batches/{id}. Cada elemento consume un DeCA del plan como una creación normal. La misma Idempotency-Key con el mismo cuerpo devuelve el mismo lote (200); nunca se duplica un DeCA.
/api/v1/batches/{id}deca:readSolo AdvancedEstado del lote y resultado de cada elemento (created, replayed, failed, pending).
status pasa de processing a completed cuando todos los elementos han terminado.
/api/v1/batches/{id}/pdfsdeca:readSolo AdvancedDescarga un ZIP con el PDF vigente de cada DeCA creado por el lote.
Responde 409 batch_without_documents si el lote aún no ha creado ninguno.
/api/v1/draftsdeca:createSolo AdvancedIdempotency-Key obligatoriaAbre un borrador nuevo e independiente (datos parciales). No consume cuota.
Responde 201 con draftId (200 si es un reintento con la misma Idempotency-Key).
/api/v1/draftsdeca:readSolo AdvancedLista los borradores: status=open (por defecto) | generated | cancelled | all.
Paginado con limit y cursor, como /decas. Los borradores son de la empresa: con deca:read_company verás también los empezados en la web (origin: "web") y los de otras integraciones, y podrás completarlos, generarlos o descartarlos.
/api/v1/drafts/{id}deca:readSolo AdvancedUn borrador, con ready e issues (lo que falta para poder generarlo).
/api/v1/drafts/{id}deca:createSolo AdvancedModifica o completa un borrador abierto (JSON Merge Patch).
Opcional If-Match con el ETag: 412 si otro cambio llegó antes.
/api/v1/drafts/{id}/generatedeca:createSolo AdvancedGenera el DeCA definitivo de ese borrador; los demás no cambian.
201 con el DeCA; repetir devuelve el mismo DeCA (200). Aquí se consume la cuota.
/api/v1/drafts/{id}deca:createSolo AdvancedDescarta un borrador abierto (queda como cancelled).
/api/v1/decas/{id}/service-completiondeca:correctSolo AdvancedMarca el servicio como finalizado (dato operativo; el DeCA, su PDF y su URL no cambian).
Cuerpo opcional { note } (hasta 500 caracteres). Idempotente: devuelve el DeCA con service.finished. 409 deca_annulled en un DeCA anulado. Webhook deca.service_finished.
/api/v1/decas/{id}/service-completiondeca:correctSolo AdvancedReabre un servicio marcado como finalizado (vuelve a pendiente).
Idempotente. Webhook deca.service_reopened.
/api/v1/load-ordersdeca:readSolo AdvancedLista las órdenes de carga: número, estado, formato (junta o separada), DeCA vinculado, matrículas pendientes y aceptación.
Filtros: decaId, status (pending_vehicle | active | cancelled), limit (1–100). Sin deca:read_company, solo las de DeCA creados por tu integración. Nunca incluye el precio ni las condiciones (están en el PDF). Para emitirla: POST /api/v1/decas con loadOrder.
/api/v1/load-orders/{id}deca:readSolo AdvancedUna orden de carga: estado, versión vigente, DeCA vinculado y aceptación del transportista.
/api/v1/load-orders/{id}/pdfdeca:readSolo AdvancedEl PDF de la versión vigente de la orden de carga.
/api/v1/saved/companiessaved:readSolo AdvancedLista las empresas habituales (cargadores y transportistas) de la empresa.
Orden de creación. Parámetros: limit (1–100, por defecto 50), cursor (nextCursor de la página anterior) y externalId (búsqueda exacta). Incluye también los registros creados en la web (externalId null).
/api/v1/saved/companies/{externalId}saved:readSolo AdvancedLee un registro por el identificador de tu ERP o TMS (externalId).
/api/v1/saved/companies/{externalId}saved:writeSolo AdvancedCrea o actualiza el registro con ese externalId (sincronización sin duplicados).
Responde 201 si lo crea y 200 si lo actualiza; repetir la misma llamada deja el mismo registro. Se valida con las mismas reglas que la web y aparece al momento en Datos habituales. Nunca cambia un DeCA ya generado.
/api/v1/saved/companies/{externalId}saved:writeSolo AdvancedBorra el registro con ese externalId.
Nunca cambia un DeCA ya generado.
/api/v1/saved/vehiclessaved:readSolo AdvancedLista los vehículos habituales (con su conductor habitual) de la empresa.
Orden de creación. Parámetros: limit (1–100, por defecto 50), cursor (nextCursor de la página anterior) y externalId (búsqueda exacta). Incluye también los registros creados en la web (externalId null).
/api/v1/saved/vehicles/{externalId}saved:readSolo AdvancedLee un registro por el identificador de tu ERP o TMS (externalId).
/api/v1/saved/vehicles/{externalId}saved:writeSolo AdvancedCrea o actualiza el registro con ese externalId (sincronización sin duplicados).
Responde 201 si lo crea y 200 si lo actualiza; repetir la misma llamada deja el mismo registro. Se valida con las mismas reglas que la web y aparece al momento en Datos habituales. Nunca cambia un DeCA ya generado.
/api/v1/saved/vehicles/{externalId}saved:writeSolo AdvancedBorra el registro con ese externalId.
Nunca cambia un DeCA ya generado.
/api/v1/saved/placessaved:readSolo AdvancedLista los lugares habituales de carga y descarga de la empresa.
Orden de creación. Parámetros: limit (1–100, por defecto 50), cursor (nextCursor de la página anterior) y externalId (búsqueda exacta). Incluye también los registros creados en la web (externalId null).
/api/v1/saved/places/{externalId}saved:readSolo AdvancedLee un registro por el identificador de tu ERP o TMS (externalId).
/api/v1/saved/places/{externalId}saved:writeSolo AdvancedCrea o actualiza el registro con ese externalId (sincronización sin duplicados).
Responde 201 si lo crea y 200 si lo actualiza; repetir la misma llamada deja el mismo registro. Se valida con las mismas reglas que la web y aparece al momento en Datos habituales. Nunca cambia un DeCA ya generado.
/api/v1/saved/places/{externalId}saved:writeSolo AdvancedBorra el registro con ese externalId.
Responde 409 saved_in_use si un envío habitual usa ese lugar.
/api/v1/saved/shipmentssaved:readSolo AdvancedLista los envíos habituales (lugar de carga + lugar de descarga + mercancía) de la empresa.
Orden de creación. Parámetros: limit (1–100, por defecto 50), cursor (nextCursor de la página anterior) y externalId (búsqueda exacta). Incluye también los registros creados en la web (externalId null).
/api/v1/saved/shipments/{externalId}saved:readSolo AdvancedLee un registro por el identificador de tu ERP o TMS (externalId).
/api/v1/saved/shipments/{externalId}saved:writeSolo AdvancedCrea o actualiza el registro con ese externalId (sincronización sin duplicados).
Responde 201 si lo crea y 200 si lo actualiza; repetir la misma llamada deja el mismo registro. Se valida con las mismas reglas que la web y aparece al momento en Datos habituales. Los lugares se indican con su externalId (loadPlaceExternalId, unloadPlaceExternalId): sincronízalos antes. Nunca cambia un DeCA ya generado.
/api/v1/saved/shipments/{externalId}saved:writeSolo AdvancedBorra el registro con ese externalId.
Nunca cambia un DeCA ya generado.
Crear un DeCA
El cuerpo describe el transporte: fechas, vehículo, cargador contractual (shipper), transportista efectivo (carrier) y de 1 a 50 envíos. Los países van siempre en código ISO de dos letras (ES, FR, PT…). Los campos desconocidos se rechazan.
| Campo | Obligatorio | Descripción |
|---|---|---|
externalId | Recomendado | Tu identificador (pedido, expedición). 1–100 caracteres: letras, números y . _ - /. Único entre los DeCA activos de la empresa. |
loadDate, unloadDate | Sí | DD-MM-AAAA. La descarga no puede ser anterior a la carga. |
vehicle.tractorPlate | Sí | Matrícula (se normaliza: mayúsculas, sin espacios ni guiones). trailerPlate opcional. |
vehicle.secondTrailerPlate | No | Segundo remolque o semirremolque (conjuntos de dos remolques). Requiere trailerPlate y debe ser distinta. |
shipper, carrier | Sí | Empresa (name, taxId, address; country, postalCode, city opcionales) o "self". |
shipments[] | Sí | loadLocation y unloadLocation (nombre, dirección, código postal, ciudad, provincia opcional, país ISO), goods, weight (número = kg, o texto como "22 palés"), recipient opcional. |
reference | No | Hasta 120 caracteres; se imprime en el DeCA. |
notes | No | Hasta 1000 caracteres, una sola línea. |
serviceType | No | goods (por defecto) o passenger (transporte de viajeros). |
groupageRef | No | Referencia común a los DeCA independientes de un grupaje (un DeCA por cargador): «G-» seguido de 6 a 16 letras o dígitos. Filtra con GET /api/v1/decas?groupageRef=…. |
loadOrder | No | Emite una orden de carga con el DeCA: format (joint, en el mismo documento, o separate), price, currency (EUR, USD, GBP, CHF), taxNote (unspecified, excluded, included), conditions, paymentTerms y billingInstructions. Solo si tu empresa es el cargador contractual y tu plan incluye la orden de carga. |
curl -X POST https://decaprofesional.es/api/v1/decas \
-H "Authorization: Bearer $DECA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @deca.json{
"externalId": "TR-45882",
"reference": "Pedido 88231",
"loadDate": "06-10-2026",
"unloadDate": "07-10-2026",
"vehicle": {
"tractorPlate": "1234 KLM",
"trailerPlate": "R-5678-BBC"
},
"shipper": {
"name": "CERÁMICAS DEL MEDITERRÁNEO S.A.",
"taxId": "A12345674",
"country": "ES",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana"
},
"carrier": "self",
"shipments": [
{
"loadLocation": {
"name": "Planta 1",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana",
"province": "Castellón",
"country": "ES"
},
"unloadLocation": {
"name": "Entrepôt Lyon Sud",
"address": "12 Rue du Port",
"postalCode": "69007",
"city": "Lyon",
"country": "FR"
},
"goods": "Azulejo cerámico en palés",
"weight": 18400,
"recipient": "Céramique Rhône SARL"
}
]
}Respuesta 201 Created con la cabecera Location: /api/v1/decas/{id}:
{
"id": "cmg4x2k9a0001l508h3n7q2rz",
"reference": "DECA-Q3VJ9KXA",
"externalId": "TR-45882",
"groupageRef": null,
"status": "active",
"availability": "public",
"version": 1,
"createdAt": "2026-10-05T09:41:12+02:00",
"updatedAt": "2026-10-05T09:41:12+02:00",
"annulledAt": null,
"service": {
"finished": false,
"finishedAt": null,
"note": null
},
"serviceType": "goods",
"servicePeriod": {
"start": "06-10-2026",
"end": "07-10-2026",
"publicUntil": "14-10-2026"
},
"verification": {
"url": "https://decaprofesional.es/d/q3vj9kxa7Rm2…",
"note": "La URL cambia con cada corrección: imprime o envía siempre la última."
},
"pdf": {
"href": "/api/v1/decas/cmg4x2k9a0001l508h3n7q2rz/pdf",
"sha256": "9f2c4e…",
"contentType": "application/pdf"
},
"data": {
"reference": "Pedido 88231",
"notes": null,
"loadDate": "06-10-2026",
"unloadDate": "07-10-2026",
"vehicle": {
"tractorPlate": "1234KLM",
"trailerPlate": "R5678BBC"
},
"currentVehicle": {
"tractorPlate": "1234KLM",
"trailerPlate": "R5678BBC"
},
"vehicleChanges": [],
"shipper": {
"name": "CERÁMICAS DEL MEDITERRÁNEO S.A.",
"taxId": "A12345674",
"country": "ES",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana"
},
"carrier": {
"name": "TRANSPORTES EJEMPLO S.L.",
"taxId": "B12345674",
"country": null,
"address": "Polígono Industrial 5",
"postalCode": "46540",
"city": "El Puig"
},
"shipments": [
{
"loadLocation": {
"name": "Planta 1",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana",
"province": "Castellón",
"country": "ES",
"countryName": "España"
},
"unloadLocation": {
"name": "Entrepôt Lyon Sud",
"address": "12 Rue du Port",
"postalCode": "69007",
"city": "Lyon",
"province": null,
"country": "FR",
"countryName": "Francia"
},
"goods": "Azulejo cerámico en palés",
"weight": "18.400 kg",
"recipient": "Céramique Rhône SARL",
"loadDate": "06-10-2026",
"unloadDate": "07-10-2026"
}
],
"totalWeight": "18.400 kg"
},
"warnings": [],
"links": {
"self": "/api/v1/decas/cmg4x2k9a0001l508h3n7q2rz",
"status": "/api/v1/decas/cmg4x2k9a0001l508h3n7q2rz/status",
"versions": "/api/v1/decas/cmg4x2k9a0001l508h3n7q2rz/versions",
"pdf": "/api/v1/decas/cmg4x2k9a0001l508h3n7q2rz/pdf"
}
}warnings recoge avisos que no impiden crear el DeCA (por ejemplo, un NIF con un formato poco habitual). availability indica si la URL pública está disponible (public), ya caducó (expired) o el DeCA está anulado (annulled).
Idempotency-Key y externalId
Idempotency-Key (cabecera, obligatoria al crear y corregir): una cadena única por operación, por ejemplo un UUID (8–255 caracteres). Si repites la misma llamada con la misma clave y el mismo cuerpo —por un corte de red o un reintento—, recibes el mismo DeCA con 200 y la cabecera Idempotent-Replayed: true; nunca se crea un segundo documento. La misma clave con un cuerpo distinto responde 409 idempotency_conflict.
externalId (cuerpo): el identificador de tu objeto de negocio. Si ya existe un DeCA activo con ese externalId, la API responde 409 duplicate_external_id con el existingId. Puedes buscarlo con GET /api/v1/decas?externalId=…. Un DeCA anulado libera su externalId.
Validar sin crear
POST /api/v1/decas/validate acepta el mismo cuerpo que la creación y aplica exactamente las mismas reglas, pero no crea ningún DeCA, no genera PDF y no consume el cupo del plan. Úsalo para probar tu integración y para comprobar los datos antes de emitir.
{
"valid": true,
"warnings": []
}“self”: tu propia empresa
En shipper o carrier puedes enviar el texto "self" en lugar de los datos de la empresa: se usan los datos de la empresa de la credencial tal como figuran en su ficha de DeCA Profesional. Si la ficha está incompleta, la respuesta es 422 con el detalle self_company_incomplete.
PDF, QR y URL de verificación
Cada DeCA tiene una URL pública de verificación (verification.url): es la que codifica el QR impreso en el PDF y la que se muestra en una inspección, sin necesidad de cuenta. El PDF se descarga con tu credencial en GET /api/v1/decas/{id}/pdf (o ?version=N); la cabecera X-Pdf-Sha256 permite comprobar su integridad. La URL pública está disponible durante el servicio y los 7 días siguientes (servicePeriod.publicUntil).

curl https://decaprofesional.es/api/v1/decas/<id>/pdf \
-H "Authorization: Bearer $DECA_API_KEY" -o deca.pdfCorrecciones
Una corrección sustituye todos los datos del DeCA y crea una nueva versión con nueva URL de verificación, nuevo QR y nuevo PDF. Las versiones anteriores se conservan (GET /versions). Imprime o envía siempre la última URL. El externalId no se puede cambiar y un DeCA anulado no se puede corregir. Responde 201 con el DeCA en su nueva versión (200 si es un reintento con la misma Idempotency-Key).
Opcionalmente envía baseVersionNo (la versión que leíste): si el DeCA ha cambiado desde entonces responde 409 version_conflict en lugar de sobrescribir. Una corrección sigue siendo el mismo transporte: si cambian a la vez las fechas, la ruta (localidades) y las partes (NIF del cargador o del transportista) respecto a la versión 1, responde 422 new_service_required y debes crear un DeCA nuevo. Las correcciones no consumen DeCA del plan.
1. POST /decas
Versión 1 con su URL de verificación.
2. POST /corrections
Versión 2 con URL, QR y PDF nuevos; la anterior se conserva.
3. Imprime o envía
Siempre la última URL.
4. POST /annulment
Definitivo: la URL muestra que el DeCA está anulado.
{
"changeReason": "Cambio de matrícula del remolque",
"deca": "…el mismo cuerpo completo que al crear…"
}Cambio de vehículo
Si la tractora (o el remolque) cambia durante el transporte, registra el cambio en lugar de crear otro DeCA. Se genera una nueva versión con nueva URL, QR y PDF, que muestra el vehículo inicial y cada cambio con su fecha; no consume DeCA del plan. La fecha debe estar dentro del transporte y puedes registrar cambios sucesivos. Consulta el historial con GET /api/v1/decas/{id}/vehicles; en el recurso del DeCA, data.currentVehicle es el vehículo actual y data.vehicleChanges la lista de cambios.
{
"tractorPlate": "5678 NPR",
"effectiveAt": "07-10-2026",
"reason": "Avería de la tractora en ruta"
}Anulación
La anulación es definitiva: la URL pública pasa a mostrar que el documento está anulado y el QR sigue resolviendo a ese aviso. Repetir la llamada devuelve 200 sin cambios. El motivo es obligatorio (3–500 caracteres).
{
"reason": "Pedido cancelado por el cliente"
}Completar un DeCA por un tercero
Si a tu ERP le faltan datos que conoce otra empresa —por ejemplo, la matrícula que asignará el transportista o la localidad exacta de descarga—, puedes crear el DeCA igualmente y pedir esos datos a un tercero. Es la misma función «Completar por la contraparte» de la web: el tercero recibe un email con un enlace seguro, rellena solo los campos que le pides y, cuando ya no falta ningún dato obligatorio, el DeCA se genera automáticamente y pasa a vigente, con su PDF, su QR y su URL de verificación. Requiere el mismo acceso que el resto de la API (plan Business con el complemento API activo).
Añade completionRequest al cuerpo de POST /api/v1/decas, con el email del destinatario (recipientEmail) y los campos que debe completar (fields). Esos campos pueden llegar vacíos; todos los demás deben ser válidos, igual que en una creación normal. La respuesta es 202 Accepted con un borrador (object: "deca_draft"), no con un DeCA vigente. Opcionalmente: recipientName, recipientType (shipper | carrier | authorized_person) y expiresInHours (1–48; por defecto 24).
| Campo que se puede pedir | Qué es |
|---|---|
vehicle.tractorPlate | Matrícula del vehículo tractor |
vehicle.trailerPlate | Matrícula del remolque o semirremolque |
shipments[N].unloadLocation | El lugar de descarga completo: name, address, postalCode y city |
shipments[N].unloadLocation.city (o .name, .address, .postalCode) | Un solo dato del lugar de descarga |
shipments[N].unloadDate | Fecha de descarga |
shipments[N].weight | Peso de la mercancía en kg de ese envío (no en servicios de viajeros). El tercero escribe solo el número (vale 12.500, 12,5 t u 800 kg) y se guarda normalizado, p. ej. «12.500 kg». Se puede pedir solo el peso aunque el resto esté completo. En un DeCA ya emitido el peso se cambia con una corrección (POST /decas/{id}/corrections). |
Igual que en la web, solo se pueden pedir las matrículas y los datos de descarga: el lugar de carga, la provincia, el país, las partes, la mercancía y el peso los aporta siempre quien crea el DeCA (si no, la API responde 422 invalid_completion_field).
{
"externalId": "TR-45882",
"loadDate": "06-10-2026",
"unloadDate": "07-10-2026",
"vehicle": {
"tractorPlate": "",
"trailerPlate": ""
},
"shipper": {
"name": "CERÁMICAS DEL MEDITERRÁNEO S.A.",
"taxId": "A12345674",
"country": "ES",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana"
},
"carrier": "self",
"shipments": [
{
"loadLocation": {
"name": "Planta 1",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana",
"country": "ES"
},
"unloadLocation": {
"name": "Almacenes Norte",
"address": "Polígono Arasur, calle C 14",
"postalCode": "01230",
"city": "",
"country": "ES"
},
"goods": "Azulejo cerámico en palés",
"weight": 18400
}
],
"completionRequest": {
"recipientEmail": "operaciones@transportista.example",
"recipientType": "carrier",
"fields": [
"vehicle.tractorPlate",
"vehicle.trailerPlate",
"shipments[0].unloadLocation.city"
]
}
}{
"id": "cmupjfyb600uvvos0tycclmsp",
"object": "deca_draft",
"status": "pending_completion",
"decaId": null,
"externalId": "TR-45882",
"missingFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate"
],
"createdAt": "2026-10-01T14:56:31+02:00",
"updatedAt": "2026-10-01T14:56:31+02:00",
"completionRequest": {
"id": "cmupjfybh00uxvos0uwlt3pjv",
"status": "pending",
"requestedFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate",
"vehicle.trailerPlate"
],
"recipientEmail": "operaciones@transportista.example",
"createdAt": "2026-10-01T14:56:31+02:00",
"expiresAt": "2026-10-02T14:56:31+02:00",
"completedAt": null
},
"warnings": []
}El enlace seguro
El enlace se envía solo por email al destinatario; la API nunca lo devuelve. Es personal, de un solo uso y caduca a las expiresInHours horas. El tercero no necesita cuenta, solo ve el nombre de tu empresa y los campos que le pides, y no puede modificar ningún otro dato. El email indica qué empresa solicita los datos, la fecha de caducidad y qué ocurre al enviarlos.
Cuando el tercero completa los datos
Los datos se validan y se incorporan al borrador. Si ya no falta ningún dato obligatorio, el DeCA se genera automáticamente con tu integración como autora ( conserva tu externalId), el borrador pasa a issued y su decaId es el DeCA vigente; el tercero recibe una copia por email. Si aún faltan datos, el borrador queda en draft y missingFields te dice cuáles.
Consultar el estado
GET /api/v1/decas/{id} responde tanto con el id del borrador como con el del DeCA ya emitido (que también incluye completionRequest). Estados del borrador:
pending_completion— Hay una solicitud abierta: el tercero aún no ha enviado los datos.draft— Faltan datos (missingFields) y no hay ninguna solicitud abierta: pide los datos o reenvía.ready— No falta nada, pero el DeCA no se pudo emitir (por ejemplo, cupo del plan agotado). Se puede emitir desde el panel.issued— El DeCA ya es vigente: consúltalo con decaId.cancelled— El borrador se canceló desde el panel.
completionRequest.status: pending, completed, expired o replaced (sustituida por un reenvío).
{
"id": "cmupjfyb600uvvos0tycclmsp",
"object": "deca_draft",
"status": "issued",
"decaId": "cmupjfyzn00vzvos06903zz7y",
"externalId": "TR-45882",
"missingFields": [],
"createdAt": "2026-10-01T14:56:31+02:00",
"updatedAt": "2026-10-01T14:56:32+02:00",
"completionRequest": {
"id": "cmupjfynd00vmvos07hmyqdfy",
"status": "completed",
"requestedFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate",
"vehicle.trailerPlate"
],
"recipientEmail": "operaciones@transportista.example",
"createdAt": "2026-10-01T14:56:32+02:00",
"expiresAt": "2026-10-02T14:56:32+02:00",
"completedAt": "2026-10-01T14:56:32+02:00"
}
}{
"id": "cmupjfyb600uvvos0tycclmsp",
"object": "deca_draft",
"status": "draft",
"decaId": null,
"externalId": "TR-45882",
"missingFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate"
],
"createdAt": "2026-10-01T14:56:31+02:00",
"updatedAt": "2026-10-01T14:56:31+02:00",
"completionRequest": {
"id": "cmupjfybh00uxvos0uwlt3pjv",
"status": "expired",
"requestedFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate",
"vehicle.trailerPlate"
],
"recipientEmail": "operaciones@transportista.example",
"createdAt": "2026-10-01T14:56:31+02:00",
"expiresAt": "2026-10-01T14:56:30+02:00",
"completedAt": null
}
}Pedir los datos después
También puedes crear primero el borrador ("draft": true en lugar de completionRequest) y pedir los datos más tarde. Si ya hay una solicitud pendiente, la respuesta es 409 completion_request_pending; si el DeCA ya es vigente, 409 deca_already_issued (usa una corrección).
{
"recipientEmail": "operaciones@transportista.example",
"fields": [
"vehicle.tractorPlate",
"shipments[0].unloadLocation.city"
],
"expiresInHours": 48
}{
"id": "cmupjfyhp00v8vos059cdhihy",
"completionRequest": {
"id": "cmupjfyij00vcvos0ga6ikvio",
"status": "pending",
"requestedFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate"
],
"recipientEmail": "operaciones@transportista.example",
"createdAt": "2026-10-01T14:56:31+02:00",
"expiresAt": "2026-10-03T14:56:31+02:00",
"completedAt": null
}
}Reenviar la solicitud
POST /api/v1/decas/{id}/completion-request/resend envía un enlace nuevo al mismo destinatario con los campos que aún no se han completado; el enlace anterior deja de funcionar. Úsalo, por ejemplo, cuando el enlace ha caducado. Cuerpo opcional: { "expiresInHours": 24 }. Máximo 5 reenvíos por borrador y hora; una solicitud ya completada responde 409 completion_request_completed.
{
"id": "cmupjfyb600uvvos0tycclmsp",
"completionRequest": {
"id": "cmupjfynd00vmvos07hmyqdfy",
"status": "pending",
"requestedFields": [
"shipments[0].unloadLocation.city",
"vehicle.tractorPlate",
"vehicle.trailerPlate"
],
"recipientEmail": "operaciones@transportista.example",
"createdAt": "2026-10-01T14:56:32+02:00",
"expiresAt": "2026-10-02T14:56:32+02:00",
"completedAt": null
}
}Seguridad e idempotencia
Una credencial solo ve y gestiona los borradores de su propia integración (con deca:read_company, puede leer todos los de su empresa). Todas estas llamadas exigen Idempotency-Key: si repites una con la misma clave, recibes la misma respuesta (200, Idempotent-Replayed: true) sin crear otro borrador, otra solicitud ni otro email. Cada paso queda registrado: quién lo pidió, cuándo se abrió el enlace, quién completó qué y cuándo se generó el DeCA.
Borradores: varios transportes a la vez
Si tu sistema prepara varios transportes en paralelo, abre un borrador por cada uno con POST /api/v1/drafts. Cada borrador es independiente y tiene su propio draftId: puedes tener todos los que necesites abiertos a la vez, completarlos poco a poco y generar cada DeCA cuando esté listo, sin que un borrador pise a otro. Un borrador no consume cuota de tu plan; la cuota se consume solo al generar el DeCA definitivo.
El cuerpo es el mismo que el de POST /api/v1/decas, pero puede estar incompleto. Cada respuesta indica ready y, si falta algo, issues con los mismos detalles de error que daría la creación directa.
Los borradores abiertos también aparecen en la web, en Mis DeCA › Borradores pendientes (con la etiqueta «API» y tu externalId), para los usuarios de tu empresa que pueden crear DeCA. Desde allí se pueden continuar en el asistente, generar o descartar. Si se genera desde la web, el borrador queda generated con su decaId (y generatedByApiCredentialId vacío); si se descarta, queda cancelled. Consúltalo con GET /api/v1/drafts/{id}.
{
"externalId": "VIAJE-4471",
"reference": "Pedido 88231",
"loadDate": "06-10-2026",
"unloadDate": "07-10-2026",
"shipper": {
"name": "CERÁMICAS DEL MEDITERRÁNEO S.A.",
"taxId": "A12345674",
"country": "ES",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana"
},
"carrier": "self"
}{
"id": "cmuqr2x0k0001vo8k3d1f9a7b",
"draftId": "cmuqr2x0k0001vo8k3d1f9a7b",
"object": "api_draft",
"origin": "api",
"status": "open",
"version": 1,
"externalId": "VIAJE-4471",
"data": {
"...": "el cuerpo que enviaste"
},
"ready": false,
"issues": [
{
"path": "/vehicle",
"code": "invalid_type",
"message": "Requerido"
},
{
"path": "/shipments",
"code": "invalid_type",
"message": "Requerido"
}
],
"decaId": null,
"generatedAt": null,
"cancelledAt": null,
"createdAt": "2026-10-02T11:12:04+02:00",
"updatedAt": "2026-10-02T11:12:04+02:00",
"links": {
"self": "/api/v1/drafts/cmuqr2x0k0001vo8k3d1f9a7b",
"generate": "/api/v1/drafts/cmuqr2x0k0001vo8k3d1f9a7b/generate"
}
}Para completarlo, envía solo lo que cambia con PATCH /api/v1/drafts/{id} (JSON Merge Patch: los objetos se combinan, las listas como shipments se sustituyen enteras y null borra un campo). Si quieres evitar sobrescribir un cambio hecho por otro proceso, envía la cabecera If-Match con el ETag que recibiste: si el borrador cambió entretanto, la respuesta es 412.
{
"vehicle": {
"tractorPlate": "1234 KLM"
},
"shipments": [
{
"loadLocation": {
"name": "Planta 1",
"address": "Carretera de Alcora km 3",
"postalCode": "12006",
"city": "Castellón de la Plana",
"country": "ES"
},
"unloadLocation": {
"name": "Almacenes Norte",
"address": "Polígono Arasur, calle C 14",
"postalCode": "01230",
"city": "Ribabellosa",
"country": "ES"
},
"goods": "Azulejo cerámico en palés",
"weight": 18400
}
]
}Cuando ready sea true, genera el DeCA con POST /api/v1/drafts/{id}/generate. Pasa exactamente las mismas validaciones y el mismo límite de plan que POST /api/v1/decas y responde 201 con el DeCA vigente (PDF, QR y URL de verificación). El borrador queda generated con su decaId y la fecha de generación; ya no se puede modificar, y repetir la llamada devuelve el mismo DeCA (200), nunca uno nuevo. El resto de borradores no cambia. GET /api/v1/drafts lista los abiertos (?status=generated, cancelled o all para el resto) y DELETE /api/v1/drafts/{id} descarta uno que ya no necesites.
Cada borrador pertenece a tu empresa y a la integración que lo creó: con otra clave, un draftId ajeno responde 404, igual que uno que no existe. Esta función es nueva y no cambia nada de lo anterior: POST /api/v1/decas con draft: true o completionRequest sigue funcionando igual.
Ejemplo completo: una operación real de transporte
Así encaja todo en un día normal: tu ERP o TMS prepara el transporte, tu equipo lo revisa en el panel si hace falta, el transportista completa las matrículas y tu sistema recibe cada paso por webhook. Cada paso es una llamada de esta página.
1. Sincroniza tus datos habituales desde el ERP
PUT /api/v1/saved/companies/CLI-0042 · PUT /api/v1/saved/places/ALM-VLCCon tu identificador estable (externalId): repetir la llamada actualiza, nunca duplica. Lo que cambies en el panel se ve en la API y al revés.
2. Crea el borrador del transporte
POST /api/v1/drafts (Idempotency-Key)Con lo que el ERP ya sabe (cargador, lugares, mercancía, fechas). Puede faltar la matrícula: responde ready=false e issues con lo pendiente. No consume cupo.
3. Continúalo desde el panel si hace falta
Mis DeCA › Borradores pendientesEl borrador aparece con la etiqueta «API» y tu externalId. Con deca:read_company tu integración ve también los borradores iniciados en la web, incluidos los programados.
4. Pide las matrículas al transportista
POST /api/v1/decas/{id}/completion-requestUn enlace temporal para que el transportista complete solo los campos pedidos. Cuando los completa recibes completion.completed (solo los nombres de los campos, nunca los valores).
5. Genera el DeCA y su orden de carga
POST /api/v1/decas con loadOrder { format: "separate", price, conditions }Un DeCA con su QR y su PDF, y la orden vinculada (junta o separada) si tu empresa es el cargador. Recibes deca.created y load_order.issued. Repetir con la misma Idempotency-Key no crea nada nuevo.
6. Recibe las confirmaciones por webhook
deca.created · load_order.issued · load_order.accepted · deca.corrected · deca.service_finishedVerifica la firma DeCA-Signature y descarta duplicados por id de evento. load_order.accepted llega cuando el transportista acepta la orden por su enlace.
7. Recupera referencias y documentos
GET /api/v1/decas/{id} · GET /api/v1/decas/{id}/pdf · GET /api/v1/load-orders?decaId={id}La referencia DECA-…, la URL de verificación, el PDF vigente, la orden con su estado y aceptación, y service.finished cuando se marca el servicio como finalizado.
Entorno de pruebas (sandbox)
Crea en Integraciones → Centro de integración una clave de pruebas: empieza por fvd_test_. Con ella tu integración llama a las mismas URL con los mismos cuerpos y recibe las mismas validaciones y errores, pero los documentos son de prueba: no son DeCA, no consumen tu cupo, no aparecen en el Historial ni en la facturación y su PDF lleva la marca «PRUEBA · SIN VALIDEZ». Cuando todo funcione, cambia la clave por una real (fvd_live_) sin tocar nada más.
- Funcionan con la clave de pruebas:
GET /me(respondemode: "test"),POST /decas/validate,POST /decas,GET /decas,GET /decas/{id},/status,/pdf,/correctionsy/annulment. El resto responde 403sandbox_not_supported. - Las respuestas llevan
livemode: false, el id empieza portest_y la referencia porPRUEBA-. - Los webhooks de tus documentos de prueba se envían a tus endpoints con
livemode: false: así pruebas también la recepción. - Hasta 2 claves de pruebas activas, aparte de las 2 reales.
Errores a demanda. Crea un documento con externalId: "PRUEBA-ERROR-<código>" y la API responderá ese error, igual que en real, para que compruebes cómo lo trata tu programa:
| externalId | HTTP | Respuesta |
|---|---|---|
| PRUEBA-ERROR-duplicate_external_id | 409 | Ya existe un DeCA activo con este externalId. |
| PRUEBA-ERROR-plan_allowance_exhausted | 402 | Has alcanzado los DeCA incluidos en tu plan este mes. |
| PRUEBA-ERROR-rate_limited | 429 | Límite de peticiones por minuto superado. |
| PRUEBA-ERROR-daily_create_ceiling | 429 | Límite técnico diario de creación alcanzado. |
| PRUEBA-ERROR-generation_failed | 500 | No se pudo generar el DeCA. Inténtalo de nuevo. |
| PRUEBA-ERROR-service_unavailable | 503 | La API no está disponible temporalmente. |
Webhooks: tu sistema se entera solo
Configura en Integraciones → Centro de integración → Webhooks la URL https:// de tu sistema y los eventos que te interesan. Cada aviso es un POST JSON firmado; tu servidor debe responder 2xx en menos de 10 segundos. Si no, reintentamos a los 1, 5 y 30 minutos y a las 2, 6, 12 y 24 horas, siempre con el mismo DeCA-Event-Id, para que puedas descartar duplicados. Desde el panel puedes enviar un evento de prueba, ver cada entrega y reenviar las fallidas.
| Evento | Cuándo |
|---|---|
| deca.created | Se crea un DeCA en tu empresa (web, API, borrador o tercero). |
| deca.corrected | Se corrige un DeCA o se registra un cambio de vehículo (nueva versión). |
| deca.annulled | Se anula un DeCA. |
| draft.generated | Un borrador de la API se convierte en DeCA. |
| completion.completed | Un tercero completa los datos que le pediste (solo los nombres de los campos, nunca los valores). |
| deca.service_finished | Se marca el servicio como finalizado (dato operativo: el DeCA, su PDF y su estado administrativo no cambian). Incluye la observación, si la hay. |
| deca.service_reopened | Se reabre un servicio marcado como finalizado (vuelve a pendiente). |
| load_order.issued | Se emite una orden de carga (con su DeCA, sola o pendiente de matrículas). Incluye número, formato, estado y el DeCA vinculado; nunca el precio ni las condiciones. |
| load_order.accepted | El transportista acepta una versión de la orden por su enlace. Incluye la versión aceptada y la fecha; el nombre escrito no se envía. |
| webhook.test | Evento de prueba enviado desde el panel. |
Cabeceras: DeCA-Event-Id, DeCA-Event-Type y DeCA-Signature con el formato t=<segundos>,v1=<HMAC-SHA256 hex de "<t>.<cuerpo>">, calculado con el secreto que se muestra una sola vez al crear el endpoint. Los avisos incluyen identificadores y referencias, no los datos personales del DeCA: consúltalos con la API si los necesitas.
{
"id": "evt_4n8Qx2kY0pLmRs7T",
"type": "deca.created",
"createdAt": "2026-10-08T10:41:00+02:00",
"livemode": true,
"data": {
"deca": {
"id": "cmupjfyhp00v8vos059cdhihy",
"reference": "DECA-A4F2C9E1",
"externalId": "TR-45882",
"status": "active",
"version": 1,
"verificationUrl": "https://decaprofesional.es/d/A4F2C9E1…",
"links": {
"self": "/api/v1/decas/cmupjfyhp00v8vos059cdhihy",
"pdf": "/api/v1/decas/cmupjfyhp00v8vos059cdhihy/pdf"
}
},
"source": "api"
}
}import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: el cuerpo EXACTO recibido (sin volver a serializarlo); secret: dcwh_… (Integraciones → Webhooks)
export function webhookValido(rawBody, signatureHeader, secret) {
const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(signatureHeader ?? "");
if (!m) return false;
if (Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false; // más de 5 min: posible reenvío malicioso
const esperado = createHmac("sha256", secret).update(`${m[1]}.${rawBody}`).digest();
const recibido = Buffer.from(m[2], "hex");
return esperado.length === recibido.length && timingSafeEqual(esperado, recibido);
}
// Responde 2xx en menos de 10 s y procesa después. Usa DeCA-Event-Id para no procesar dos veces el mismo evento.Power Automate y Make: conectar sin escribir código
Si tu ERP o TMS ya se conecta con Power Automate o con Make (Odoo, Sage, Holded, Dynamics y muchos más lo hacen), puedes generar DeCA sin escribir código: la herramienta lee la expedición de tu sistema y llama a la API. Lo que no podemos hacer por ti es que tu programa exporte sus datos: eso depende de que tenga integración con estas herramientas o una API propia. No son integraciones nativas: te damos la definición para crear un conector personalizado y una guía paso a paso.
Power Automate (Microsoft)
Un conector personalizado con todas las llamadas de la API, creado a partir del archivo Swagger del kit. Después cada llamada aparece como una acción más en tus flujos.
- Descarga deca-power-automate.swagger.json (enlace de abajo).
- En Power Automate, abre Datos → Conectores personalizados → Nuevo conector personalizado → Importar un archivo OpenAPI, ponle de nombre «DeCA Profesional» y elige el archivo.
- En Seguridad, deja «Clave de API», con el nombre de parámetro Authorization y la ubicación Encabezado.
- Pulsa «Crear conector». En Prueba, crea una conexión y pega como clave: Bearer seguido de tu clave de API (créala en Integraciones → Centro de integración).
- Prueba GET /api/v1/me: si responde con el nombre de tu empresa, la conexión funciona.
- En tu flujo (por ejemplo, «cuando se crea un albarán en Dynamics, SharePoint o Excel»), añade la acción «Crea un DeCA» y relaciona cada campo con el de tu sistema según la tabla de equivalencias.
Los conectores personalizados necesitan una licencia de Power Automate que los incluya (Premium). Pon un valor distinto en Idempotency-Key en cada expedición, por ejemplo la función guid().
Make
Con el módulo HTTP «Make a request» llamas a cualquier endpoint, y con «Webhooks → Custom webhook» recibes los avisos de DeCA Profesional.
- Añade el módulo HTTP → Make a request.
- URL: https://decaprofesional.es/api/v1/decas · Método: POST.
- Cabeceras: Authorization = Bearer <tu clave> · Idempotency-Key = {{uuid}} · Content-Type = application/json.
- Body type: Raw · Content type: JSON (application/json) · Request content: el JSON del DeCA con los campos de tu ERP mapeados (tabla de equivalencias). Marca «Parse response».
- Para recibir avisos, crea un módulo Webhooks → Custom webhook, copia su URL https y añádela en Integraciones → Centro de integración → Webhooks.
- Para mantener tus datos habituales al día, usa el mismo módulo HTTP con PUT /api/v1/saved/{recurso}/{externalId} y el código de tu ERP como externalId.
Guarda la clave en una conexión o variable de Make, nunca en un texto visible del escenario. Si tu escenario no puede verificar la firma de los webhooks, usa solo el id del evento y lee el DeCA con la API.
Tabla de equivalencias: de tu ERP a la API
El concepto es el mismo en cualquier ERP; la columna de Odoo indica el campo estándar de sus módulos Inventario, Contactos y Flota. En Sage, Holded o Dynamics busca el campo equivalente: el nombre exacto depende de cada instalación.
| En tu ERP | Campo de la API | Ejemplo en Odoo | Consejo |
|---|---|---|---|
| Número de albarán o expedición | externalId | stock.picking · name | Único por expedición: evita duplicados. |
| Fecha de carga | loadDate | stock.picking · scheduled_date | En DD-MM-AAAA. |
| Fecha de descarga | unloadDate | stock.picking · date_deadline | En DD-MM-AAAA; igual o posterior a la carga. |
| Cargador (cliente o tu empresa) | shipper | res.partner · name, vat, street, zip, city | "self" si eres tú. |
| Transportista | carrier | res.partner del transportista | "self" si transportas tú. |
| Matrícula de la tractora | vehicle.tractorPlate | fleet.vehicle · license_plate | Con o sin espacios ni guiones. |
| Matrícula del remolque | vehicle.trailerPlate | fleet.vehicle · license_plate | Opcional. |
| Almacén o dirección de carga | shipments[0].loadLocation | stock.picking · picking_type_id.warehouse_id.partner_id | name, address, postalCode, city, country. |
| Dirección de entrega | shipments[0].unloadLocation | stock.picking · partner_id | Si falta, pídela a la otra parte (completionRequest). |
| Descripción de la mercancía | shipments[0].goods | stock.move · product_id.name | Texto breve, por ejemplo «Palés de azulejo». |
| Peso | shipments[0].weight | stock.picking · weight | Número en kg o texto con su unidad. |
Permisos (scopes)
Cada credencial tiene solo los permisos que necesita su integración.
| deca:create | Crear DeCA (POST /decas, también por lotes) y validarlos (POST /decas/validate), crear, modificar y generar borradores, y pedir datos a un tercero. |
| deca:read | Leer y listar los DeCA creados por esta integración, sus borradores, lotes y órdenes de carga. |
| deca:read_company | Ampliar la lectura a todos los DeCA de la empresa. Nunca amplía la escritura. |
| deca:correct | Corregir DeCA creados por esta integración, registrar cambios de vehículo y marcar o reabrir el servicio finalizado. |
| deca:annul | Anular DeCA creados por esta integración. |
| saved:read | Leer los datos habituales de la empresa: empresas, vehículos, lugares y envíos habituales. |
| saved:write | Crear, actualizar (PUT por externalId) y borrar datos habituales desde tu ERP o TMS. |
Límites
- 60 peticiones por minuto por credencial (cabeceras
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset). - Un techo técnico diario de creación por credencial (5000 DeCA) y un bloqueo temporal tras varios intentos de autenticación fallidos.
- Cuerpo de hasta 256 KB y hasta 50 envíos por DeCA.
- El cupo mensual de DeCA es el de tu plan;
GET /api/v1/meindica el uso y lo que queda. - Al superar un límite recibes
429conRetry-After: espera y reintenta.
Errores
Todos los errores tienen el mismo formato. code es estable y es lo que debe leer tu integración; message es informativo. Si contactas con soporte, indica el requestId.
{
"error": {
"code": "validation",
"message": "El DeCA no cumple los requisitos obligatorios.",
"requestId": "req_7f3a9c…",
"details": [
{
"path": "/shipments/0/unloadLocation/country",
"code": "invalid_country",
"message": "Usa un código de país ISO 3166-1 alfa-2 (p. ej. ES, FR, PT)"
}
]
}
}| HTTP | code | Significado |
|---|---|---|
| 400 | invalid_json, idempotency_key_required, invalid_query | Petición mal formada, falta la Idempotency-Key o un filtro no es válido. |
| 401 | invalid_credentials, credential_revoked, credential_expired | Clave desconocida o incorrecta (misma respuesta en ambos casos), revocada o caducada. |
| 402 | business_plan_required, plan_allowance_exhausted | El plan de la empresa no incluye la API, o se ha agotado el cupo de DeCA del plan. |
| 403 | api_addon_required, api_advanced_required, professional_plan_required, company_inactive, ip_not_allowed, insufficient_scope, sandbox_not_supported | El complemento API no está activo, la cuenta no está activa, IP no autorizada, permiso insuficiente o endpoint no disponible con una clave de pruebas. |
| 429 | api_lite_limit_reached | API Lite: ya se han creado por API los 100 DeCA del mes (dentro del cupo del plan). Se renueva con el periodo del plan; para más, API Advanced. |
| 404 | not_found | No existe o no es visible para esta credencial (nunca se distingue). |
| 409 | duplicate_external_id, idempotency_conflict, deca_annulled, version_conflict, batch_without_documents, saved_in_use, company_inactive | externalId ya usado por un DeCA activo (incluye existingId), clave de idempotencia reutilizada con otro cuerpo, DeCA anulado, corrección simultánea o lote que aún no ha creado ningún DeCA, lugar habitual usado por un envío habitual, o la empresa no tiene un Administrador al sincronizar datos habituales. |
| 402 / 403 / 409 / 422 | load_order_plan_required, load_order_not_shipper, load_order_company_nif_missing, load_order_invalid, load_order_passenger | Orden de carga con POST /decas (loadOrder): el plan no incluye la orden de carga (402), tu empresa no es el cargador contractual (403), falta el NIF de tu empresa (409), los datos comerciales no son válidos (422, details indica el campo en /loadOrder/…) o el servicio es de viajeros (422). No se crea ningún DeCA. |
| 409 | deca_already_issued, completion_request_pending, completion_request_completed, draft_cancelled | Solicitudes a un tercero: el DeCA ya es vigente (usa una corrección), ya hay una solicitud pendiente (usa /resend), la solicitud ya se completó, o el borrador se canceló. |
| 409 | draft_not_open, draft_limit_reached, draft_has_preparation, completion_request_no_email | Borradores: ya generado o cancelado, límite de borradores abiertos alcanzado (incluye limit), borrador web vinculado a una solicitud a un tercero (genéralo con /api/v1/decas/{id}), o la solicitud no tiene email de destinatario. |
| 412 | precondition_failed | If-Match no corresponde: el borrador ha cambiado desde tu última lectura. Vuelve a leerlo (cabecera ETag) y aplica tu cambio de nuevo. |
| 404 | completion_request_not_found | Reenvío pedido para un DeCA sin ninguna solicitud a un tercero. |
| 422 | invalid_draft, invalid_completion_request, new_service_required | El borrador o el cambio no es un objeto JSON válido (o incluye campos solo de POST /decas), la solicitud a un tercero no es válida, o la corrección cambia el servicio (crea un DeCA nuevo). |
| 413 / 415 | payload_too_large, unsupported_media_type | Cuerpo de más de 256 KB, o no es application/json. |
| 422 | validation | Datos no válidos. details indica cada campo con un puntero JSON y un código (required, unknown_field, invalid_country, too_short, too_long, invalid_format, invalid_value, self_company_incomplete…). |
| 422 | invalid_completion_field | Un campo de completionRequest.fields no se puede pedir a un tercero (unknown_field) o se refiere a un envío que no existe (unknown_shipment). |
| 429 | rate_limited, daily_create_ceiling, too_many_failed_attempts | Límite de peticiones superado. Respeta la cabecera Retry-After. |
| 500 | generation_failed, internal_error | Error al generar (incluye correlationId y retryable: reintenta con la misma Idempotency-Key) o error interno. |
| 503 | service_unavailable, pdf_unavailable | Servicio o PDF temporalmente no disponible: reintenta. |
Preguntas frecuentes
¿Qué hace la API DeCA de DeCA Profesional que no haga una integración básica?
Además de crear el DeCA con su PDF y QR, permite corregirlo (nueva versión), registrar un cambio de vehículo, anularlo, trabajar con borradores, pedir a un tercero los datos que faltan, crear lotes de hasta 50 DeCA en una llamada con un ZIP de los PDF y recibir webhooks firmados cuando algo cambia. Todo está descrito en una especificación OpenAPI y hay ejemplos listos para Node.js, Python, PHP, Postman y Power Automate.
¿Puedo recibir un aviso en mi ERP cuando se crea, corrige o anula un DeCA?
Sí, con webhooks: das de alta una URL https en el centro de integración y recibes un aviso firmado (DeCA-Signature) por cada DeCA creado, corregido o anulado, borrador generado, solicitud completada por un tercero, servicio finalizado o reabierto, y orden de carga emitida o aceptada. Si tu servidor no responde, se reintenta automáticamente y el identificador del evento no cambia, para que no lo proceses dos veces.
¿Puedo generar muchos DeCA a la vez?
Sí: POST /api/v1/decas/batch crea hasta 50 DeCA en una sola llamada. Cada uno se valida y se crea por separado, un error no afecta a los demás, un reintento con la misma Idempotency-Key no duplica nada y puedes descargar todos los PDF en un ZIP.
¿Dónde pongo la clave de la API?
No se introduce en DeCA Profesional: se configura en tu propio programa de gestión (ERP o TMS), normalmente lo hace tu informático o el proveedor de ese programa. Con ella, tu programa envía los datos del transporte a DeCA Profesional y recibe al momento el DeCA, su PDF con QR y la URL de verificación, sin que nadie tenga que rellenarlo en la web. Si no usas un ERP o TMS, o no tienes a nadie que haga la integración, no necesitas la API: puedes crear tus DeCA desde la web.
¿Hay un entorno de pruebas?
Sí. Crea una clave de pruebas (empieza por fvd_test_) en Integraciones → Centro de integración: llamas a las mismas URL y recibes las mismas validaciones, pero los documentos son de prueba, no consumen cupo, no aparecen en el Historial y su PDF lleva la marca PRUEBA. Con externalId PRUEBA-ERROR-<código> reproduces errores. Y si solo quieres validar un cuerpo, POST /api/v1/decas/validate no crea nada.
¿Qué pasa si se corta la conexión mientras creo un DeCA?
Repite la misma llamada con la misma Idempotency-Key y el mismo cuerpo: si el DeCA ya se creó, recibes ese mismo DeCA (200 e Idempotent-Replayed: true); nunca se duplica.
¿Cómo evito crear dos DeCA para el mismo pedido?
Envía tu identificador de pedido o expedición en externalId. Si ya hay un DeCA activo con ese externalId, la API responde 409 duplicate_external_id con el existingId, y puedes consultarlo con GET /api/v1/decas?externalId=….
¿El QR cambia si corrijo el DeCA?
Sí. Cada corrección crea una versión nueva con nueva URL de verificación, nuevo QR y nuevo PDF. Guarda y comparte siempre la última verification.url; las versiones anteriores se conservan en GET /versions.
¿Puedo corregir o anular desde la API un DeCA creado en el panel?
No. La API solo corrige y anula los DeCA creados por la misma integración. Con el permiso deca:read_company puedes leer todos los DeCA de la empresa, pero nunca modificarlos.
¿Cuántos DeCA puedo crear?
Los de tu plan: los DeCA creados por la API y desde el panel comparten el mismo cupo mensual. GET /api/v1/me te indica cuántos llevas este mes y cuántos te quedan.
¿En qué formato van los países y las fechas?
Países en código ISO 3166-1 de dos letras (ES, FR, PT…) y fechas en DD-MM-AAAA (las horas, en hora de Madrid con su desfase, p. ej. 2026-10-08T10:41:00+02:00). El PDF muestra el nombre del país en español.
¿Puedo crear un DeCA aunque me falten la matrícula o el lugar de descarga?
Sí, si se los pides a un tercero: envía completionRequest con su email y los campos que faltan (por ejemplo vehicle.tractorPlate). Se crea un borrador, el tercero recibe un enlace seguro y, cuando lo completa, el DeCA se genera automáticamente. Consulta el estado con GET /api/v1/decas/{id}.
¿Cuánto tiempo está disponible la URL pública?
Durante el servicio y los 7 días siguientes a la fecha de descarga (servicePeriod.publicUntil). Con tu credencial puedes descargar el PDF en cualquier momento.
Soporte para integraciones
¿Vas a conectar tu ERP o TMS?
Cuéntanos qué software usas y te ayudamos con el acceso, las credenciales y las primeras pruebas.
Escribir a integraciones@praetoriaabogados.es