¿Ya tienes tu propio ERP o software de gestión de transporte?
Aprovecha el motor de DeCAFacil sin cambiar de herramienta: emite el DeCA directamente desde tu sistema, con la misma trazabilidad y el mismo QR legal que la aplicación web. Esta página es la documentación de referencia del canal /api/v1 para quien va a integrarlo.
Las claves de API son una mejora de la plan Pro (precio y condiciones en precios y tarifas): hace falta tenerla activa para crear y gestionar tus claves desde /claves-api. Fechas y condiciones de cobro en precios y tarifas — ver también modo de pruebas y condiciones.
Última actualización: 2 de octubre de 2026.
Qué es y para quién es
El canal de API está pensado para la misma empresa que hoy usaría la aplicación web, pero emitiendo desde su propio software en vez de entrar en la PWA. No es una API abierta para programadores en general: la clave pertenece a la empresa (identificada por su NIF), no a quien escribe la integración, y esa empresa debe figurar siempre como cargador contractual o transportista efectivo en cada DeCA que emita por esta vía — la misma regla de «parte activa» que rige el resto del servicio.
El valor práctico: no mantener dos bases de datos. DeCAFacil no necesita ni usa tus maestros de clientes, vehículos o direcciones — le mandas los datos del envío, genera el documento con su código QR, y tu sistema sigue siendo la única fuente de verdad para todo lo demás.
Cómo empezar
- Da de alta tu empresa en DeCAFacil — como cualquier cuenta, con nombre y NIF, desde la aplicación. La clave de API cuelga de una cuenta real, no hay atajos.
- Activa el plan Pro — desde
/planesdentro de la aplicación. Precio y fechas en precios y tarifas (ver condiciones). - Crea tu clave tú mismo — en
/claves-api: le pones un identificador para reconocerla, aceptas el anexo de términos de la API y se genera al momento. El secreto se muestra una única vez: apúntalo en un lugar seguro en cuanto lo veas, porque ni nosotros podemos volver a mostrártelo.
Autenticación
Cada petición lleva la clave en la cabecera:
Authorization: Bearer <tu-clave>
Nada impide tener varias claves para la misma empresa (por ejemplo, una para oficina y otra para almacén): todas identifican a la misma titular y se pueden revocar por separado.
Cada clave lleva sus permisos (scopes): leer, crear, modificar, finalizar, avisar, anular y, desde la revisión 1.1.0, asignar. El rol oficina los incluye todos. Las claves oficina ya emitidas reciben asignar automáticamente; las de otros roles o con permisos elegidos a mano, no. Una clave equivale al titular de su cuenta: no está ligada a una persona concreta.
Qué puedes hacer
La referencia completa de peticiones y respuestas está disponible en la documentación interactiva (Swagger) y en el esquema OpenAPI. Estas son las operaciones disponibles en /api/v1:
- Emitir un DeCA nuevo, con soporte de identificador propio para evitar duplicados si reintentas una petición.
- Consultar un DeCA por su identificador, listar los tuyos con paginación, y descargar el PDF vigente.
- Modificar un DeCA durante el servicio (fraccionar o eliminar envíos, con la misma lógica que la PWA).
- Finalizar el servicio, cuando corresponda.
- Avisar al conductor del documento generado.
- Anular un DeCA.
- Asignar un DeCA a una persona de tu equipo, o quitar la asignación (
POST /deca/{id}/asignar, permisoasignar). Es una mejora del plan Pro y requiere que el equipo tenga a alguien más que el titular. - Listar las personas activas de tu cuenta, con su identificador, nombre y rol, para saber a quién asignar (
GET /personas, permisoleer). No devuelve correo ni teléfono.
Las respuestas de DeCA incluyen además dos campos opcionales, creado_por_persona_id y asignado_a_persona_id, y el listado de DeCA admite el filtro asignado_a=<id> o asignado_a=ninguno.
Ejemplos de código
Nota sobre estos ejemplos. Emiten el mismo DeCA de ejemplo (Cargas Ejemplo SA → Transportes Ejemplo SL, Getafe → Valencia) que usa el resto de esta documentación. Sustituye <tu-clave> por tu clave real y, si no tienes una todavía, empieza por cómo empezar.
cURL
curl -X POST https://app.decafacil.es/api/v1/deca \
-H "Authorization: Bearer <tu-clave>" \
-H "Content-Type: application/json" \
-d '{
"datos": {
"cargador_contractual": {
"nombre": "Cargas Ejemplo SA",
"nif": "A76543214",
"direccion": {
"empresa": "Cargas Ejemplo SA",
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
}
},
"transportista_efectivo": {
"nombre": "Transportes Ejemplo SL",
"nif": "B12345674",
"direccion": {
"empresa": "Transportes Ejemplo SL",
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
}
},
"matricula_vehiculo": "1234ABC",
"envios": [
{
"origen": {
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
},
"destino": {
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
},
"mercancia": {
"naturaleza": "Palets de material de construcción",
"peso_kg": 8200,
"bultos": 12
},
"fecha_efectiva_servicio": "2026-08-28"
}
]
},
"ejecutado_por": "Nombre Apellido",
"external_id": "PED-2026-0842"
}'
Python
Con la librería requests (pip install requests):
import requests
respuesta = requests.post(
"https://app.decafacil.es/api/v1/deca",
headers={"Authorization": "Bearer <tu-clave>"},
json={
"datos": {
"cargador_contractual": {
"nombre": "Cargas Ejemplo SA",
"nif": "A76543214",
"direccion": {
"empresa": "Cargas Ejemplo SA",
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
}
},
"transportista_efectivo": {
"nombre": "Transportes Ejemplo SL",
"nif": "B12345674",
"direccion": {
"empresa": "Transportes Ejemplo SL",
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
}
},
"matricula_vehiculo": "1234ABC",
"envios": [
{
"origen": {
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
},
"destino": {
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
},
"mercancia": {
"naturaleza": "Palets de material de construcción",
"peso_kg": 8200,
"bultos": 12
},
"fecha_efectiva_servicio": "2026-08-28"
}
]
},
"ejecutado_por": "Nombre Apellido",
"external_id": "PED-2026-0842"
},
)
respuesta.raise_for_status()
print(respuesta.json())
Node.js
Con el fetch incluido en Node 18 y versiones posteriores, sin dependencias:
const respuesta = await fetch("https://app.decafacil.es/api/v1/deca", {
method: "POST",
headers: {
Authorization: "Bearer <tu-clave>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"datos": {
"cargador_contractual": {
"nombre": "Cargas Ejemplo SA",
"nif": "A76543214",
"direccion": {
"empresa": "Cargas Ejemplo SA",
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
}
},
"transportista_efectivo": {
"nombre": "Transportes Ejemplo SL",
"nif": "B12345674",
"direccion": {
"empresa": "Transportes Ejemplo SL",
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
}
},
"matricula_vehiculo": "1234ABC",
"envios": [
{
"origen": {
"via": "Calle Mayor 12",
"localidad": "Getafe",
"provincia": "Madrid",
"codigo_postal": "28901",
"pais": "España"
},
"destino": {
"via": "Polígono Industrial, Nave 4",
"localidad": "Valencia",
"provincia": "Valencia",
"codigo_postal": "46001",
"pais": "España"
},
"mercancia": {
"naturaleza": "Palets de material de construcción",
"peso_kg": 8200,
"bultos": 12
},
"fecha_efectiva_servicio": "2026-08-28"
}
]
},
"ejecutado_por": "Nombre Apellido",
"external_id": "PED-2026-0842"
}),
});
if (!respuesta.ok) {
throw new Error(`Error ${respuesta.status}: ${await respuesta.text()}`);
}
console.log(await respuesta.json());
PHP
Con la extensión curl, incluida por defecto en la mayoría de instalaciones de PHP:
<?php
$datos = [
"datos" => [
"cargador_contractual" => [
"nombre" => "Cargas Ejemplo SA",
"nif" => "A76543214",
"direccion" => [
"empresa" => "Cargas Ejemplo SA",
"via" => "Calle Mayor 12",
"localidad" => "Getafe",
"provincia" => "Madrid",
"codigo_postal" => "28901",
"pais" => "España",
],
],
"transportista_efectivo" => [
"nombre" => "Transportes Ejemplo SL",
"nif" => "B12345674",
"direccion" => [
"empresa" => "Transportes Ejemplo SL",
"via" => "Polígono Industrial, Nave 4",
"localidad" => "Valencia",
"provincia" => "Valencia",
"codigo_postal" => "46001",
"pais" => "España",
],
],
"matricula_vehiculo" => "1234ABC",
"envios" => [
[
"origen" => [
"via" => "Calle Mayor 12",
"localidad" => "Getafe",
"provincia" => "Madrid",
"codigo_postal" => "28901",
"pais" => "España",
],
"destino" => [
"via" => "Polígono Industrial, Nave 4",
"localidad" => "Valencia",
"provincia" => "Valencia",
"codigo_postal" => "46001",
"pais" => "España",
],
"mercancia" => [
"naturaleza" => "Palets de material de construcción",
"peso_kg" => 8200,
"bultos" => 12,
],
"fecha_efectiva_servicio" => "2026-08-28",
],
],
],
"ejecutado_por" => "Nombre Apellido",
"external_id" => "PED-2026-0842",
];
$ch = curl_init("https://app.decafacil.es/api/v1/deca");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <tu-clave>",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode($datos),
]);
$respuesta = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $respuesta;
Respuesta
Los cuatro ejemplos anteriores, si la clave y los datos son correctos, devuelven 201 Created con el mismo cuerpo:
{
"id": 4213,
"token": "a1b2c3d4e5f6",
"url": "https://d.decafacil.es/d/a1b2c3d4e5f6",
"n_version": 1,
"external_id": "PED-2026-0842"
}
Asignar un DeCA a una persona del equipo (cURL)
Con el identificador de persona obtenido de GET /personas. Enviar null quita la asignación:
curl -X POST https://app.decafacil.es/api/v1/deca/4213/asignar \
-H "Authorization: Bearer <tu-clave>" \
-H "Content-Type: application/json" \
-d '{"persona_id": 17}'
Respuesta 200:
{"id": 4213, "asignado_a_persona_id": 17, "anterior": null}
Si la persona no es válida (inactiva, de otra cuenta o el propio titular) la respuesta es un error con el formato habitual:
{"detail": {"code": "persona_no_asignable", "mensaje": "..."}}
Documentación interactiva y colección Postman
Si prefieres explorar el esquema completo en vez de leerlo aquí: documentación interactiva (Swagger) — prueba cada operación desde el navegador con tu propia clave — o su equivalente en ReDoc. El esquema en bruto está en /api/v1/openapi.json (OpenAPI 3.1), por si tu herramienta genera un cliente a partir de él.
Para probar la API sin escribir nada: descarga la colección Postman (en el orden natural de una integración: verificación, emitir, consultar, modificar, avisar/finalizar, anular, y la carpeta «3 bis. Equipo y asignación», con la prueba de asignación de la revisión 1.1.0). Si la cuenta no tiene el plan Pro activo o el equipo solo cuenta con el titular, los 403 de esas peticiones son el resultado esperado. Trae una guarda de seguridad incorporada — bloquea sola cualquier ejecución si detecta que la clave no está en modo de pruebas, para que un «Run collection» sin pensar no emita DeCA reales.
Errores
Todos los errores de /api/v1 — validación de datos incluida — llevan la misma forma, con un código estable para que tu integración pueda distinguir un caso de otro sin depender del texto:
{"detail": {"code": "external_id_duplicado", "mensaje": "..."}}
El texto en mensaje ya viene traducido al español (incluidos los errores de validación de campos). Sin soporte de integración dedicado (ver condiciones), este mensaje es, en la práctica, tu primera línea de soporte.
Modo de pruebas
Al crear una clave en /claves-api eliges entre real y pruebas: con una clave de pruebas, los documentos que generes quedan marcados de forma visible en el PDF y no se cuentan como emisiones reales. Es el entorno recomendado para probar tu integración antes de pasar a una clave real — puedes tener las dos a la vez, cada una con su propio secreto.
Webhooks
Los webhooks están disponibles. Con suscripción activa, el titular puede crear hasta cinco destinos activos desde Webhooks, en la aplicación. Cada destino se configura para un modo —real o pruebas— y para los eventos que quiera recibir. Al crearlo se acepta el anexo de términos. Los avisos corresponden a documentos propios de la cuenta, tanto si se emitieron desde la PWA como desde la API; no se notifican operaciones sobre documentos de terceros. La configuración se hace con la sesión de la aplicación: no añade rutas ni credenciales al esquema de /api/v1.
El destino debe ser una URL HTTPS pública por el puerto 443. No se siguen redirecciones. Guarda el secreto completo, que empieza por whsec_, al crear o rotar el destino: no vuelve a mostrarse.
| Evento | Cuándo se emite |
|---|---|
deca.creado | Al emitir un documento; lleva external_id si la API lo recibió. |
deca.finalizado | Finalización manual desde PWA/API o automática por ciclo de vida; indica automatico. |
deca.modificado | Corrección de un documento existente; informa método, versión y nombres de campos cambiados. |
deca.reemplazado | Se emite un documento nuevo que sustituye al anterior. |
deca.anulado | Anulación desde PWA/API. |
deca.expirado | La URL pública alcanza su fecha de expiración. |
deca.asignado | Cambia la persona del equipo asignada al documento. |
webhook.test | Evento sintético generado por el botón «Enviar prueba». |
Formato del aviso
Cada entrega es un POST con JSON UTF-8. El sobre es estable: id es el identificador único del evento, type su tipo, created_at la fecha de creación, mode el modo del documento y data los datos específicos del evento.
{
"id": "evt_…",
"type": "deca.finalizado",
"created_at": "2026-10-04T12:00:00Z",
"mode": "real",
"data": {
"deca_id": 123,
"estado": "finalizado",
"automatico": false,
"origen": "api"
}
}
Todos los eventos de documento incluyen deca_id y origen (pwa, api o sistema). Además, deca.creado incluye external_id y n_version; deca.finalizado incluye estado, fin_servicio, url_expira_en y automatico; deca.modificado y deca.reemplazado incluyen metodo, n_version, campos, reemplaza_a_id y reemplazado_por_id; deca.anulado y deca.expirado incluyen estado y, cuando corresponde, url_expira_en; y deca.asignado incluye persona_anterior_id y persona_nueva_id. El evento webhook.test solo contiene un mensaje de prueba. Los avisos no incluyen el contenido legal del DeCA ni los datos personales de sus partes.
Verificación de firma
Cada petición incluye X-DeCA-Event-ID, X-DeCA-Timestamp y X-DeCA-Signature: t=<timestamp>,v1=<firma_hex>. Calcula HMAC-SHA256 con el secreto como clave y, como mensaje, los bytes ASCII del timestamp, un punto y el cuerpo HTTP original. Verifica la firma con comparación constante antes de interpretar el JSON:
import hashlib, hmac
def verificar_webhook(secret: str, timestamp: str, signature: str, raw_body: bytes) -> bool:
recibida = dict(parte.split("=", 1) for parte in signature.split(","))
esperado = hmac.new(secret.encode(), timestamp.encode("ascii") + b"." + raw_body,
hashlib.sha256).hexdigest()
return (recibida.get("t") == timestamp
and hmac.compare_digest(recibida.get("v1", ""), esperado))
Confirmación y reintentos
Rechaza marcas de tiempo fuera de la ventana que defina tu servicio y deduplica por X-DeCA-Event-ID. Responde rápido con cualquier código 2xx; cualquier otro resultado, un error de red o una espera agotada se reintenta. La entrega es al menos una vez: puede repetirse y el orden de recepción no está garantizado.
Se realizan como máximo diez intentos, con esperas de 1 minuto, 5 minutos, 15 minutos, 1 hora, 6 horas, 12 horas y después 24 horas entre reintentos. Consulta en la aplicación el estado y los últimos intentos de cada destino. No hay SLA.
Límites y buen uso
El canal aplica límites de frecuencia por clave; si los superas, la respuesta indica cuánto esperar antes de reintentar (cabecera Retry-After). Se aplican además los mismos límites de documentos que al resto del servicio: los de tu plan más 500 por cada Módulo500; si los superas te avisamos y te pedimos que revises tu suscripción, y la emisión solo se bloquea cuando el exceso supera los 150 documentos.
Versionado y compatibilidad
/api/v1 es la única versión del canal por ahora, y la mantenemos estable: los cambios dentro de v1 son siempre aditivos — campos nuevos opcionales, operaciones nuevas — nunca un campo que desaparece o cambia de significado. Si alguna vez hiciera falta un cambio incompatible, se abriría como /api/v2 en paralelo, avisando con antelación a quien tenga clave activa, en vez de desactivar v1 de un día para otro.
Historial de revisiones
- 4 de octubre de 2026. Se incorporan los webhooks salientes: configuración de destinos desde la aplicación, eventos de ciclo de vida del DeCA, firma HMAC-SHA256 y reintentos. Esta incorporación no añade ni modifica rutas de
/api/v1. - 1.1.0 · 2 de octubre de 2026. Asignación de DeCA a personas del equipo: operaciones
POST /deca/{id}/asignaryGET /personas, permiso nuevoasignar(incluido en el roloficina), camposcreado_por_persona_idyasignado_a_persona_iden las respuestas de DeCA y filtroasignado_aen el listado. Cambio aditivo: no rompe ninguna integración existente.
Para que tu integración no dependa de detalles que sí pueden cambiar: programa siempre contra el code del error (sección anterior), nunca contra el texto de mensaje — ese texto puede mejorar con el tiempo sin que sea, en ningún caso, un cambio que rompa nada.
Condiciones
El uso de este canal se rige, además de por las condiciones generales del servicio, por el anexo de términos de la API: custodia de credenciales, destinos webhook, tarifa, alcance del soporte y ausencia de SLA. Se acepta al solicitar una clave o al crear un destino webhook, no antes.
Preguntas frecuentes
¿Esto sustituye a la aplicación web?
¿Puedo tener varias claves para la misma empresa?
Mi ERP es un servicio de un tercero (SaaS). ¿Quién responde de los datos ahí?
¿Cuánto cuesta?
¿Cómo sé si un DeCA cambió después de emitirlo (por ejemplo, si alguien lo corrigió o lo finalizó por teléfono)?
2xx. Las entregas pueden repetirse y no garantizan orden.¿Puedo asignar un DeCA a un conductor o empleado desde la API?
GET /personas y asigna con POST /deca/{id}/asignar (permiso asignar, incluido en el rol oficina). La relación es de una persona por documento, sin histórico.¿Tienes ya cuenta en DeCAFacil?
Activa la suscripción y crea tu clave tú mismo desde «Mis claves de API», sin esperar a que te contestemos.
Activar suscripción →Seguir leyendo
- Crear el DeCA con DeCAFacilCómo resolver cada porte desde la aplicación web.
- Qué datos lleva el DeCALos ocho apartados del artículo 6, uno a uno — el contenido que también genera esta API.
- DeCA electrónico en vigor: a quién afectaA quién afecta, qué transportes quedan fuera y qué cambia.
Esta página describe el estado actual del canal de API, en evolución. Si algo no coincide con lo que ves al integrarlo, escríbenos y lo corregimos.