DeCAya

API de DeCAya para desarrolladores

La API de DeCAya permite emitir el Documento electrónico de Control Administrativo desde tu ERP, TMS o sistema de gestión, sin pasar por el panel. Es la misma capa que usa la aplicación web: cuota, numeración, plazos de la URL de inspección y trazabilidad se comportan exactamente igual.

URL base

https://decaya.es/api/v1

Autenticación

Cada petición lleva una clave de organización en la cabecera Authorization. Las claves se crean en Ajustes → Claves de API y solo se muestran una vez: guardamos únicamente su hash.

Authorization: Bearer dcy_live_a1b2c3d4_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Entornos

El entorno lo determina la clave, nunca el cuerpo de la petición. Una clave dcy_test_… emite documentos marcados como prueba, con su propia numeración (TEST-2026-000001) y sin consumir cuota. Una clave dcy_live_… emite DeCAs reales (DEC-2026-000001). Ninguna de las dos ve los datos de la otra.

Permisos

Cada clave lleva la lista de permisos que puede ejercer:

  • documents:read
  • documents:write
  • documents:generate
  • parties:read
  • parties:write
  • vehicles:read
  • vehicles:write
  • webhooks:manage

Una petición sin el permiso necesario responde 403 INSUFFICIENT_SCOPE. Concede solo lo que la integración use.

Emitir un DeCA

curl -X POST https://decaya.es/api/v1/documents \
  -H "Authorization: Bearer $DECAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-4821" \
  -d '{
    "contractualShipperName": "Transportes García S.L.",
    "contractualShipperTaxId": "B12345678",
    "contractualShipperAddress": "Calle Mayor 1, 28001 Madrid",
    "effectiveCarrierName": "Logística Norte S.L.",
    "effectiveCarrierTaxId": "B87654321",
    "origin": "Madrid",
    "destination": "Valencia",
    "goodsDescription": "Palés de alimentación",
    "goodsWeightKg": "8450",
    "transportDate": "2026-10-05",
    "vehicleRegistration": "1234 ABC",
    "externalId": "SO-4821",
    "externalSource": "sap"
  }'

La respuesta 201 ya contiene el documento emitido, con su número, la URL de inspección del QR y la lista de versiones.

Borradores

Un transporte se arma por partes: primero la carga, luego el vehículo, luego el conductor. No hace falta guardar ese estado a medias en tu ERP y llamarnos solo al final: crea un borrador con lo que sepas y te decimos qué falta.

POST /api/v1/documents/drafts   -> crea, sin número ni PDF ni cuota
PATCH /api/v1/documents/{id}    -> completa el borrador
POST /api/v1/documents/{id}/issue -> lo emite

La respuesta de un borrador incluye validation:

"validation": {
  "valid": false,
  "missingFields": ["vehicleRegistration", "transportDate"]
}

Nada regulado ni facturable ocurre hasta issue: ahí se exigen todos los campos del artículo 6, se reserva el número, se genera el PDF con su QR y se consume una unidad de tu plan. Un borrador incompleto responde 400 con la lista entera de campos que faltan, no de uno en uno, y el borrador se queda como estaba.

Por eso los permisos se separan: documents:write basta para preparar borradores y documents:generate es el único que puede gastar cuota. Una integración que solo prepara transportes nunca necesita el segundo.

Emitir dos veces el mismo borrador responde 409 DOCUMENT_NOT_DRAFT: un DeCA emitido ya no se edita, se modifica con /versions, que crea una versión nueva.

Campos obligatorios

Se corresponden con el artículo 6 de la Orden FOM/2861/2012 (ver datos obligatorios del DeCA):

  • contractualShipperName
  • contractualShipperTaxId
  • contractualShipperAddress
  • effectiveCarrierName
  • effectiveCarrierTaxId
  • origin
  • destination
  • goodsDescription
  • goodsWeightKg
  • transportDate
  • vehicleRegistration

Opcionales: trailerRegistration, specialAuthorization, observations y hasta nueve additionalShipments cuando el cargador contractual y el transportista efectivo son los mismos.

Tus propias referencias

externalId junto con externalSource es único por organización y entorno: si tu ERP reintenta una emisión que ya se hizo, la segunda petición recibe 409 EXTERNAL_ID_ALREADY_USED en lugar de crear un duplicado. En metadata puedes guardar pares clave-valor propios; no aparecen en el PDF ni afectan al cumplimiento.

Datos maestros: partes y vehículos

En lugar de repetir el nombre, el NIF y la dirección en cada emisión, puedes guardarlos una vez y referenciarlos. Llamamos parte al cargador contractual y al transportista efectivo porque la Orden los define como persona física o jurídica: un autónomo es una parte tanto como una S.L.

curl -X POST https://decaya.es/api/v1/parties \
  -H "Authorization: Bearer $DECAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Transportes García S.L.",
    "taxId": "B12345678",
    "address": "Calle Mayor 1, 28001 Madrid",
    "externalId": "83921",
    "externalSource": "sap"
  }'

externalId es tu identificador, no el nuestro: con él sincronizas "el cliente 83921 de mi ERP" sin buscar antes por NIF ni por nombre. Es único por externalSource, así que dos ERPs distintos pueden usar el mismo número.

Los vehículos funcionan igual y distinguen kind: "tractor" de kind: "trailer", porque la unidad de transporte del DeCA son dos matrículas y no una.

Emitir por referencia

{
  "contractualShipperPartyId": "...",
  "effectiveCarrierPartyId": "...",
  "vehicleId": "...",
  "trailerId": "...",
  "origin": "Madrid",
  "destination": "Valencia",
  "goodsDescription": "Palés de alimentación",
  "goodsWeightKg": "8450",
  "transportDate": "2026-10-05"
}

Puedes seguir enviando los datos en línea: la referencia es una comodidad, no una obligación. Lo que no aceptamos es una referencia y su dato equivalente en la misma petición (400 REFERENCE_AND_VALUE_CONFLICT): no hay una lectura obviamente correcta de esa mezcla y preferimos no adivinar sobre un documento regulado.

Un DeCA emitido no cambia nunca

Al emitir, los valores se copian al documento. Si mañana corriges el nombre o la dirección de una parte, el DeCA ya emitido sigue diciendo lo que decía: es el registro de un transporte que ocurrió con esos datos, y el agente que lo inspeccione un año después tiene derecho a lo que era cierto entonces. La corrección solo afecta a los documentos que emitas a partir de ese momento.

Si lo que cambia es el propio transporte, eso es una modificación y tiene su propio camino: POST /api/v1/documents/{id}/versions.

Idempotencia

Envía Idempotency-Key en toda petición que cree algo. Si se corta la conexión y reintentas con la misma clave y el mismo cuerpo, devolvemos la respuesta original con la cabecera Idempotent-Replayed: true en vez de emitir un segundo DeCA. La misma clave con un cuerpo distinto se rechaza con 409 IDEMPOTENCY_KEY_REUSED. Las claves caducan a las 24 horas.

Endpoints

Método y rutaPermisoQué hace
POST /api/v1/documentsdocuments:generateEmite un DeCA y devuelve su PDF y su URL de inspección.
GET /api/v1/documentsdocuments:readLista con filtros status, external_id, external_source, transport_date y paginación por starting_after.
GET /api/v1/documents/{id}documents:readUn documento con todas sus versiones.
POST /api/v1/documents/draftsdocuments:writeBorrador: sin número, sin PDF y sin consumir cuota.
PATCH /api/v1/documents/{id}documents:writeCompleta un borrador. No toca los DeCA ya emitidos.
POST /api/v1/documents/{id}/issuedocuments:generateEmite el borrador: número, PDF, QR y cuota.
POST /api/v1/documents/{id}/versionsdocuments:generateModificación: nueva versión con PDF, URL y QR nuevos. No consume cuota.
POST /api/v1/documents/{id}/completedocuments:writeMarca el servicio como finalizado.
POST /api/v1/documents/{id}/canceldocuments:writeAnula el documento. El PDF se conserva igualmente.
POST /api/v1/documents/{id}/senddocuments:writeEnvía al conductor la última versión (o la que indiques).
GET /api/v1/documents/{id}/pdfdocuments:readDescarga el PDF almacenado. Con ?version=N para una versión concreta.
GET|POST /api/v1/partiesparties:read / parties:writeCargadores y transportistas reutilizables.
GET|PATCH /api/v1/parties/{id}parties:read / parties:writeEditar no altera los DeCA ya emitidos.
GET|POST /api/v1/vehiclesvehicles:read / vehicles:writeVehículos y remolques, con filtro por kind.
GET|PATCH /api/v1/vehicles/{id}vehicles:read / vehicles:writeUn vehículo concreto.
GET /api/v1/usagedocuments:readDocumentos emitidos este mes y plan en vigor.
GET /api/v1/webhook-endpointswebhooks:manageGestión de webhooks.

La especificación completa está en /api/v1/openapi.json.

Enviar el DeCA al conductor

curl -X POST https://decaya.es/api/v1/documents/{id}/send \
  -H "Authorization: Bearer $DECAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: envio-4821" \
  -d '{"to": "conductor@example.com"}'

Enviamos un correo con el enlace de descarga directa y el PDF adjunto. Por defecto va la última versión, que es justo la que el conductor debe llevar después de una modificación; con versionNumber puedes forzar otra.

Usa Idempotency-Key: aquí importa más que en ningún otro sitio, porque un reintento tras un timeout metería un segundo correo en la bandeja del conductor y es así como acaba abriendo el que no toca.

Modificaciones

La Resolución de 5 de junio de 2026 permite modificar un DeCA emitido conservando el original. DeCAya aplica el método B: cada modificación genera una versión nueva con su propio PDF, su propia URL y su propio QR, y las anteriores siguen accesibles. El conductor debe recibir el enlace nuevo: el anterior sigue vivo, pero ya no refleja los datos vigentes. Para eso está POST /api/v1/documents/{id}/send.

Límite de peticiones

El límite se aplica por clave, no por IP, así que una integración ruidosa no afecta a otra organización ni te penaliza por cambiar de servidor. Cada respuesta incluye la política vigente:

RateLimit-Policy: 120;w=60

Al superarlo respondemos 429 RATE_LIMITED con Retry-After. No publicamos un contador de peticiones restantes porque no disponemos de ese dato: preferimos no inventarlo.

Errores

Todos los errores comparten el mismo sobre:

{
  "error": {
    "type": "validation_error",
    "code": "REQUIRED_FIELD_MISSING",
    "message": "Falta el campo transportDate.",
    "field": "transportDate"
  }
}

Ramifica siempre por code, nunca por message: los mensajes son texto para personas y pueden cambiar.

EstadoCuándo
400Datos inválidos o incompletos.
401Clave ausente, caducada o revocada.
403La clave no tiene el permiso necesario.
402Cuota mensual del plan agotada.
404No existe en esta organización y entorno.
409Conflicto: idempotencia, estado o externalId.

Toda respuesta incluye X-Request-Id. Si envías tu propio valor en la petición, lo devolvemos tal cual y queda registrado en la auditoría del documento, lo que hace trivial cruzar un problema con tus logs.

Siguiente paso

Crea una clave de pruebas en Ajustes, emite un DeCA de prueba y suscríbete a los webhooks para enterarte de cada emisión, modificación o anulación. Si aún estás evaluando la herramienta, empieza por software DeCA.

DeCAya llega muy pronto: tu DeCA listo en segundos

Conocer DeCAya →

Fuentes oficiales

La información de esta página se basa en la normativa publicada por el Ministerio de Transportes y Movilidad Sostenible y el Boletín Oficial del Estado.

Última revisión:

Consultar MinisterioConsultar BOE