TuControlDeRutas

El documento en papel deja de ser válido el 5 de octubre de 2026

Solicita acceso →

Para desarrolladores · Plan ESCALA

API REST y Webhooks para tu ERP o TMS

Crea documentos de control (DeCA) directamente desde tu sistema y recibe avisos firmados en cada cambio de estado. Integración bidireccional con el patrón estándar REST + webhooks, sin tarifa por integración.

REST sobre HTTPSAutenticación BearerWebhooks firmados HMAC-SHA256Idempotente

1. Cómo empezar

  1. Necesitas el plan ESCALA.
  2. En el panel, ve a Ajustes → API y crea una clave con permiso de escritura.
  3. Guarda la clave (tcr_…): solo se muestra una vez.
  4. Empléala en la cabecera Authorization de cada petición.

2. Autenticación

Todas las llamadas requieren tu clave como Bearer token:

Authorization: Bearer tcr_TU_CLAVE

Base de la API: https://app.tucontrolderutas.com

3. Crear un DeCA

POST

/api/v1/documentos

Crea un documento de control. Queda emitido y válido ante inspección al instante.

Campos obligatorios (los datos del art. 6 · Orden FOM/2861/2012)

expedidor_nombreCargador contractual (razón social)
expedidor_nifNIF/CIF del cargador
transportista_nombreTransportista efectivo
transportista_nifNIF/CIF del transportista
origen_direccionDirección de origen
origen_ciudadCiudad de origen
destino_direccionDirección de destino
destino_ciudadCiudad de destino
descripcion_mercanciasNaturaleza de la mercancía
fecha_hora_previstaFecha/hora del transporte (ISO 8601)
matricula_vehiculoMatrícula del vehículo

Campos opcionales

referencia_externaTu nº de pedido. Clave de idempotencia (ver abajo)
precio_referenciaPrecio o referencia al contrato. NO es dato del DeCA (es de la carta de porte)
expedidor_direccionDomicilio del cargador
origen_cp / destino_cpCódigos postales
peso_kgPeso bruto en kg
remolque_matriculaMatrícula del remolque
tipo_vehiculo"rigido" (def.) o "articulado"
conductor_nombre / conductor_dni_nieDatos del conductor (opcional, no es dato del art. 6)
num_bultosNúmero de bultos
referencia_clienteTu referencia interna (libre)
tipo_mercancia / numero_onu / clase_adrMercancías peligrosas (ADR)
observaciones / instrucciones_entregaTexto libre

Ejemplo

curl -X POST https://app.tucontrolderutas.com/api/v1/documentos \
  -H "Authorization: Bearer tcr_TU_CLAVE" \
  -H "Content-Type: application/json" \
  -d '{
    "referencia_externa": "PEDIDO-2026-00123",
    "expedidor_nombre": "Logística Ebro SL",
    "expedidor_nif": "B12345678",
    "transportista_nombre": "Trans López SL",
    "transportista_nif": "B87654321",
    "origen_direccion": "Pol. Ind. Malpica, nave 7",
    "origen_ciudad": "Zaragoza",
    "destino_direccion": "C/ Embajadores 120",
    "destino_ciudad": "Madrid",
    "descripcion_mercancias": "22 palés de bebidas",
    "fecha_hora_prevista": "2026-06-20T08:15",
    "matricula_vehiculo": "4521KTM",
    "precio_referencia": "870 €"
  }'

Respuesta 201 Created

{
  "ok": true,
  "idempotente": false,
  "documento": {
    "id": "a846a916-7b39-4d81-b5d7-dede94a25702",
    "numero_control": "70268072",
    "estado": "emitido",
    "referencia_externa": "PEDIDO-2026-00123",
    "pdf_url": "https://.../documentos/.../70268072.pdf",
    "url_inspeccion": "https://app.tucontrolderutas.com/inspeccion/a846a916-...",
    "url_pdf_publico": "https://app.tucontrolderutas.com/api/pdf/v/a846a916-...",
    "created_at": "2026-06-20T06:15:02Z"
  }
}

Tipos de documento (campo modo)

El mismo endpoint crea los tres tipos. modo_b (carta de porte como DeCA) queda pendiente de firma AdES y no es válido hasta que firman expedidor y transportista. eCMR es para transporte internacional.

# Por defecto crea un DeCA. Para otros tipos, añade "modo":

# modo_b · carta de porte como DeCA (requiere firma AdES)
{ "modo": "modo_b", ...campos del DeCA...,
  "destinatario_nombre": "Distribuciones Sur SL",
  "destinatario_direccion": "C/ Sevilla 10, Madrid",
  "email_expedidor": "firma@ebro.com",
  "email_transportista": "firma@translopez.com" }
# → queda "pendiente_firma_aes"; se envían los enlaces de firma a ambas partes.

# eCMR · carta de porte internacional (requiere firma AdES)
{ "modo": "ecmr", ...campos del DeCA...,
  "pais_origen": "ES", "pais_destino": "FR",
  "valor_mercancias": 18000, "moneda": "EUR",
  "email_expedidor": "firma@ebro.com",
  "email_transportista": "firma@translopez.com" }
# → queda "pendiente_firma_aes"; se envían los enlaces de firma a ambas partes.

4. Idempotencia

Envía tu número de pedido en referencia_externa. Si repites la llamada con la misma referencia, la API no duplica el documento: devuelve el ya creado con 200 OK e idempotente: true. Así tu ERP puede reintentar tras un timeout sin riesgo de crear DeCAs duplicados.

5. Consultar

GET

/api/v1/documentos?estado=&desde=&hasta=&pagina=&limite=

Lista paginada de documentos (máx. 200 por página).

GET

/api/v1/documentos/:id

Un documento con todos sus campos y firmas.

GET

/api/v1/conductores

Conductores de la empresa.

GET

/api/v1/vehiculos

Vehículos de la empresa.

6. Sincronizar maestros

Da de alta conductores y vehículos desde tu ERP. Idempotente por la clave natural (dni_nie / matricula): si ya existen, se devuelven sin duplicar. Los vehículos respetan el límite de tu plan.

POST

/api/v1/conductores

Alta de conductor (nombre, apellidos, dni_nie obligatorios).

POST

/api/v1/vehiculos

Alta de vehículo (matricula obligatoria; tipo: rigido/articulado/furgon).

# Alta de conductor (idempotente por dni_nie)
curl -X POST https://app.tucontrolderutas.com/api/v1/conductores \
  -H "Authorization: Bearer tcr_TU_CLAVE" -H "Content-Type: application/json" \
  -d '{ "nombre": "Juan", "apellidos": "Martín Ruiz",
        "dni_nie": "51234829V", "telefono": "612345678" }'

# Alta de vehículo (idempotente por matrícula)
curl -X POST https://app.tucontrolderutas.com/api/v1/vehiculos \
  -H "Authorization: Bearer tcr_TU_CLAVE" -H "Content-Type: application/json" \
  -d '{ "matricula": "4521KTM", "tipo": "articulado" }'

7. Webhooks

Registra una URL en Ajustes → API → Webhooks y te enviaremos un POST cada vez que un documento cambie de estado, sin que tengas que sondear la API.

Eventos

documento.emitidoDeCA creado y válido ante inspección
documento.firmado_cargadorEl cargador ha firmado
documento.firmado_conductorEl conductor ha firmado
documento.firmado_receptorEl destinatario ha firmado
documento.completadoEntrega completada
documento.entrega_rechazadaEl destinatario rechazó la entrega
documento.finalizadoServicio finalizado (arranca el plazo de cierre del QR; la ley permite cerrarlo a partir de 7 días)

Qué recibes

POST  https://tu-erp.com/webhooks/tcr
X-TCR-Evento: documento.completado
X-TCR-Firma:  sha256=2b1c...   ← HMAC-SHA256 del cuerpo con tu secret

{
  "evento": "documento.completado",
  "enviado_at": "2026-06-20T14:32:10Z",
  "documento": {
    "id": "a846a916-...",
    "numero_control": "70268072",
    "estado": "completado",
    "referencia_externa": "PEDIDO-2026-00123",
    "pdf_url": "https://.../70268072.pdf",
    "url_inspeccion": "https://app.tucontrolderutas.com/inspeccion/a846a916-...",
    "origen_ciudad": "Zaragoza",
    "destino_ciudad": "Madrid"
  }
}

Verificar la firma

Cada envío incluye X-TCR-Firma: sha256=…, el HMAC-SHA256 del cuerpo crudo con el secret de tu webhook. Compáralo antes de procesar:

// Node.js (Express)
const crypto = require('crypto')

app.post('/webhooks/tcr', express.raw({ type: '*/*' }), (req, res) => {
  const firma = req.headers['x-tcr-firma']
  const esperado = 'sha256=' + crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(req.body)            // cuerpo crudo, sin parsear
    .digest('hex')

  if (!crypto.timingSafeEqual(Buffer.from(firma), Buffer.from(esperado)))
    return res.status(401).end()

  const evento = JSON.parse(req.body)
  // … actualiza tu ERP …
  res.status(200).end()
})
<?php // PHP
$cuerpo = file_get_contents('php://input');
$firma  = $_SERVER['HTTP_X_TCR_FIRMA'] ?? '';
$esperado = 'sha256=' . hash_hmac('sha256', $cuerpo, $WEBHOOK_SECRET);

if (!hash_equals($esperado, $firma)) { http_response_code(401); exit; }

$evento = json_decode($cuerpo, true);
// … actualiza tu ERP …
http_response_code(200);

8. Errores y límites

400Cuerpo JSON no válido
401API key ausente, inválida o revocada
403La empresa no es ESCALA, o la clave es de solo lectura
422Validación: faltan campos obligatorios (campo detalles[])
429Límite de 120 creaciones/minuto por clave superado

¿List@ para integrar?

Crea tu cuenta, activa el plan ESCALA y genera tu primera clave en minutos.