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/v1Autenticació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_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxEntornos
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:readdocuments:writedocuments:generateparties:readparties:writevehicles:readvehicles:writewebhooks: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 emiteLa 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):
contractualShipperNamecontractualShipperTaxIdcontractualShipperAddresseffectiveCarrierNameeffectiveCarrierTaxIdorigindestinationgoodsDescriptiongoodsWeightKgtransportDatevehicleRegistration
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 ruta | Permiso | Qué hace |
|---|---|---|
POST /api/v1/documents | documents:generate | Emite un DeCA y devuelve su PDF y su URL de inspección. |
GET /api/v1/documents | documents:read | Lista con filtros status, external_id, external_source, transport_date y paginación por starting_after. |
GET /api/v1/documents/{id} | documents:read | Un documento con todas sus versiones. |
POST /api/v1/documents/drafts | documents:write | Borrador: sin número, sin PDF y sin consumir cuota. |
PATCH /api/v1/documents/{id} | documents:write | Completa un borrador. No toca los DeCA ya emitidos. |
POST /api/v1/documents/{id}/issue | documents:generate | Emite el borrador: número, PDF, QR y cuota. |
POST /api/v1/documents/{id}/versions | documents:generate | Modificación: nueva versión con PDF, URL y QR nuevos. No consume cuota. |
POST /api/v1/documents/{id}/complete | documents:write | Marca el servicio como finalizado. |
POST /api/v1/documents/{id}/cancel | documents:write | Anula el documento. El PDF se conserva igualmente. |
POST /api/v1/documents/{id}/send | documents:write | Envía al conductor la última versión (o la que indiques). |
GET /api/v1/documents/{id}/pdf | documents:read | Descarga el PDF almacenado. Con ?version=N para una versión concreta. |
GET|POST /api/v1/parties | parties:read / parties:write | Cargadores y transportistas reutilizables. |
GET|PATCH /api/v1/parties/{id} | parties:read / parties:write | Editar no altera los DeCA ya emitidos. |
GET|POST /api/v1/vehicles | vehicles:read / vehicles:write | Vehículos y remolques, con filtro por kind. |
GET|PATCH /api/v1/vehicles/{id} | vehicles:read / vehicles:write | Un vehículo concreto. |
GET /api/v1/usage | documents:read | Documentos emitidos este mes y plan en vigor. |
GET /api/v1/webhook-endpoints | webhooks:manage | Gestió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=60Al 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.
| Estado | Cuándo |
|---|---|
400 | Datos inválidos o incompletos. |
401 | Clave ausente, caducada o revocada. |
403 | La clave no tiene el permiso necesario. |
402 | Cuota mensual del plan agotada. |
404 | No existe en esta organización y entorno. |
409 | Conflicto: 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 →