RiskRouter evidence log

Endpoint MCP alojado para un registro de evidencia a prueba de manipulaciones. Sin una clave, lee cabezales firmados, pruebas de inclusión y consistencia, y puntos de control; con una, registra el SHA-256 con sal de un registro de decisión. El registro en sí nunca sale de tu lado.

Servidor MCP alojado

npx add-mcp 'https://api.riskrouter.eu/mcp'

Se instala en Claude Code, Codex, Cursor y más

Documentación

No hay SDK que instalar ni nada que licenciar. El motor es un endpoint HTTP, la matriz de tarifas se publica en otro, y el libro de auditoría es una sola tabla. Todo lo que aparece a continuación se ejecuta ahora mismo contra la compilación de validación en vivo.

Cotiza una configuración en una sola solicitud

Sin clave, sin cuenta, sin sesión. Envía una vertical y los componentes que el cliente activó. Obtienes un precio real. Registrar esa cotización en el libro de auditoría es una decisión separada, y es la que necesita una clave — obtén una clave de sandbox ahora, o lee Claves y el rastro de auditoría primero.

curl -X POST https://api.riskrouter.eu/api/v1/quote \
  -H 'Content-Type: application/json' \
  -d '{
        "active_vertical": "urban_rental",
        "selected_components": { "deposit_liquidity_swap": true, "smart_home_iot": true }
      }'

Recibes partidas con precio, un total, el estado normalizado de componentes que usó el motor, y un informe separado de si se intentó una escritura de auditoría y si se completó.

Desde un backend Node

const res = await fetch('https://api.riskrouter.eu/api/v1/quote', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    active_vertical: 'mobility',
    selected_components: { commuter_roadside: true }
  })
});

const quote = await res.json();
if (!res.ok || quote.ok !== true) throw new Error(quote.error?.code ?? \`HTTP ${res.status}\`);

// Show this. Never show a number your own code calculated.
const total = quote.quote.totals.total_monthly_premium;   // "3.00"

// A 200 does not mean a record exists. Check the write separately.
// Without an API key this is false by design, not by failure.
const recorded = quote.persistence.persisted === true;

Desde Python

import requests

r = requests.post(
    "https://api.riskrouter.eu/api/v1/quote",
    json={"active_vertical": "micro_travel",
          "selected_components": {"winter_sports_gear": True}},
    timeout=10,
)
r.raise_for_status()
quote = r.json()

total    = quote["quote"]["totals"]["total_monthly_premium"]   # "6.00"
recorded = quote["persistence"]["persisted"] is True

Registra, exporta y verifica en cinco minutos, sin escribirle a nadie

Una clave de sandbox registra cotizaciones en el libro real, exactamente igual que una clave que emitimos a mano. La obtienes en esta página, una vez. No pedimos nada sobre ti y no almacenamos nada sobre ti: sin cuenta, sin correo, sin nombre. Solo se guarda un resumen SHA-256 de la clave.

¿Tu clave está registrando y tu evidencia es válida?

Pega una clave y esta página le pide a la API tu exportación, y luego la verifica aquí: que la clave sea reconocida, cuántas entradas ha registrado, que la cadena enlace hasta la cabecera publicada, y que hayamos firmado esa cabecera. La clave se envía solo a api.riskrouter.eu, no se almacena, y desaparece cuando abandonas la página.

La fijación de precios es abierta. El registro es atribuido.

El libro es a prueba de manipulaciones: cada entrada sella la anterior. Eso es lo que le da valor ante un auditor, y también es por lo que la ruta de escritura no puede ser abierta. Una entrada escrita por nadie en particular queda sellada permanentemente, y eliminarla después rompería cada resumen posterior. Así que el motor trata tres casos de manera diferente, y el tercero es el punto clave.

Tú envíasTú recibesLibro
Sin claveUn precio real, de inmediatoNada escrito. attribution.mode es ANONYMOUS
Una clave válidaUn precio realRegistrado contra tu distribuidor, dentro de la cadena hash
Una clave inválida, revocada o suspendidaHTTP 401, sin precioNada escrito

Una clave mala se rechaza de plano y nunca se degrada silenciosamente a una cotización anónima. La alternativa parece más amable y es mucho peor: un distribuidor cuya clave fue mal escrita o revocada seguiría recibiendo 200 durante meses, creyendo que estaba construyendo un rastro de auditoría, y descubriría durante la auditoría que no se había escrito nada. Ruidoso ahora es mejor que silencioso después.

curl -X POST https://api.riskrouter.eu/api/v1/quote \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $RISKROUTER_API_KEY" \
  -H "Idempotency-Key: order-4711" \
  -d '{ "active_vertical": "mobility", "selected_components": { "commuter_roadside": true } }'
// Two different questions. Ask both.
const priced   = quote.ok === true;                        // is this number real
const recorded = quote.attribution.recorded === true;      // is it in the ledger

Almacenamos el SHA-256 de tu clave, nunca la clave. Eso significa que no podemos mostrártela de nuevo, no podemos enviártela por correo, y no podemos recuperarla si la pierdes — solo podemos revocarla y emitir otra. También significa que una brecha en nuestra base de datos no le da a nadie la capacidad de escribir en tu rastro de auditoría.

Las claves son por entorno. Una clave de sandbox y una clave de producción son filas separadas y resúmenes separados, así que una cotización de prueba nunca puede terminar en un libro de producción por accidente.

Cómo recuperar tu evidencia

La misma clave la exporta. Este es el endpoint para conectar a un trabajo mensual desde el primer día, no el día que lo necesites.

curl -s -H "Authorization: Bearer $RISKROUTER_API_KEY" \
  https://api.riskrouter.eu/api/v1/ledger/export > "ledger-$(date +%F).json"

Recibes tus entradas completas, el esqueleto de resúmenes de toda la cadena en la que se encuentran, y la atestación firmada para la cabecera. Dos scripts de Node de la biblioteca estándar verifican los tres, sin conexión, sin clave nuestra y sin llamarnos — clona github.com/aniljangrabe-dev/riskrouter-verify, un repositorio público separado que no comparte código con este:

git clone https://github.com/aniljangrabe-dev/riskrouter-verify
node riskrouter-verify/tools/verify-attestation.mjs ledger-2026-09-20.json   # we signed this head
node riskrouter-verify/tools/verify-ledger.mjs      ledger-2026-09-20.json   # your entries produce it

Consérvalos. Una exportación que descargaste el año pasado aún se verifica después de que hayamos dejado de contestar el teléfono, que es la única respuesta honesta a ¿qué pasa con mi rastro de auditoría si ustedes quiebran?. También es por lo que no hay SDK ni nada que licenciar: un producto del que es difícil salir es un producto que tiene que serlo, y preferimos no necesitarlo.

Código funcional en el idioma en que está escrito tu producto

Cada ejemplo cotiza una cotización, la registra con una clave de idempotencia y reintenta sin registrar dos veces, registra una huella con sal de una nota de demandas y necesidades, exporta la evidencia y prueba una entrada. Solo biblioteca estándar, sin SDK que instalar, y cada uno se ejecuta en cada cambio contra el motor real, con su salida verificada por dos verificadores independientes.

Evidencia desde donde tus decisiones ya se registran

Si tu sistema ya registra sus decisiones, a través de logging de Python, a través de spans de OpenTelemetry, o a través de una función que devuelve una decisión, un registrador convierte eso en evidencia sin un proyecto de integración. Canonicaliza cada registro, lo sala y lo conserva, con su sal, en un diario de tu lado; solo el resumen y el tipo se envían, en lotes, a este registro, a tu propia instancia, o a ninguno. Un registro se escribe en el diario antes de que se envíe su resumen, así que una interrupción nunca pierde uno, y se marca como registrado solo cuando el registro lo dice. Sin dependencias, y nunca una condición para usar la API.

# Python: a log line with extra={"evidence": record} becomes evidence
log.addHandler(EvidenceHandler(Recorder(api_key=KEY, journal="evidence.jsonl")))
log.info("referred", extra={"evidence": {"kind": "ai.decision", "record_id": "dec-2292", "outcome": "refer"}})

// Node: OpenTelemetry spans with evidence.kind become evidence
provider.addSpanProcessor(new EvidenceSpanProcessor(createRecorder({ apiKey: KEY, journal: './evidence.jsonl' })));
  • Python (3.8+, biblioteca estándar): pip install riskrouter-recorder, o los archivos: riskrouter_recorder, con un manejador logging, un decorador y un procesador de spans de OpenTelemetry, y agents.py. README
  • Node (20+, sin dependencias): npm install riskrouter-recorder, o los archivos: recorder.mjs, con withEvidence y un procesador de spans de OpenTelemetry; agents.mjs y mcp-server.mjs. README

Agentes de IA. Los mismos paquetes incluyen adaptadores para los frameworks con los que se construyen los agentes: un manejador de callbacks para LangChain y LangGraph (Python y JavaScript) y un procesador de trazado para el SDK de OpenAI Agents (ambos lenguajes). Cada ejecución de agente se convierte en un registro, con sus llamadas a herramientas, llamadas a modelos, traspasos, salvaguardas y nodos de grafo como pasos; cada paso conserva un SHA-256 del texto que manejó, no el texto. Un servidor MCP le da a cualquier cliente MCP una herramienta record_decision; lo que registra es la declaración propia del agente, y así lo dice.

# LangGraph: every run of the graph becomes one record
graph.invoke(state, config={"callbacks": [EvidenceCallbackHandler(recorder, fields={"system_ref": "claims-agent"})]})

// OpenAI Agents SDK (JavaScript)
addTraceProcessor(new EvidenceTracingProcessor(recorder, { fields: { system_ref: 'claims-agent' } }));

bundle(record_digest) te da el registro, su sal y la prueba, que un supervisor verifica sin conexión con cualquiera de los verificadores. Ambos registradores se prueban en cada cambio contra el motor real y los SDK reales de OpenTelemetry, LangChain, OpenAI Agents y MCP. Están licenciados bajo Apache-2.0, como los verificadores, la suite de conformidad y el kit de integración anterior. Ambos se publican como riskrouter-recorder, en PyPI y npm; los archivos anteriores son el mismo código, si prefieres copiarlos.

Nada omitido. Dale a un registrador un secreto de cadena y cada registro entra en una cadena de completitud numerada: el registrador agrega los campos de cadena él mismo y continúa desde su diario después de un reinicio, y completeness() devuelve la lista firmada del registro de la cadena con cada registro dentro, lista para que un auditor verifique que no falta ninguno.

recorder = Recorder(chain_secret=os.environ["RISKROUTER_CHAIN_SECRET"], chain="kyc-desk")

En el OpenTelemetry Collector. otlp-sealer.mjs toma OTLP/HTTP JSON de un Collector como cualquier otro backend, y convierte spans y registros de log que llevan evidence.kind en registros, sin ninguna biblioteca dentro de la aplicación. Un lote se responde solo una vez que está en el diario, así que el Collector reintenta cualquier cosa no conservada.

RISKROUTER_API_KEY=... node otlp-sealer.mjs --port 4319 --journal /var/lib/evidence/journal.jsonl --chain otel

Archivos guardados en otro lugar. Un registro puede nombrar un archivo que no contiene, como una grabación de llamada, una factura o un lanzamiento: digest_file(path) en Python, digestFile(path) en Node, transmite su SHA-256 y el archivo permanece donde está.

Registros de seguridad. logseal.mjs sella cualquier flujo de log (journalctl, tail -F, un relay de syslog) segmento por segmento, así que después de un incidente puedes demostrar que ningún segmento sellado fue cambiado o eliminado. Los segmentos permanecen en tu propio archivo. Registros de seguridad sellados

Conecta un agente de IA a través de MCP

El registro de evidencia habla el Protocolo de Contexto de Modelo, así que un asistente de IA o framework de agentes puede leer el registro, obtener pruebas y registrar resúmenes sin que nadie escriba una integración. Agrega este servidor a cualquier cliente MCP:

https://api.riskrouter.eu/mcp
{ "mcpServers": { "riskrouter": {
    "type": "http", "url": "https://api.riskrouter.eu/mcp",
    "headers": { "Authorization": "Bearer <your key, only to record>" } } } }

Leer no necesita clave. record_evidence toma el SHA-256 de un registro que conservas y un tipo corto, nunca el registro, y necesita tu clave; una clave de sandbox toma un minuto. Cada herramienta es la misma ruta que en la referencia de API, con las mismas verificaciones. No hay herramienta de precios. Para registrar desde el proceso propio del agente en su lugar, con el registro conservado en tu diario, usa el servidor MCP local y los adaptadores de framework anteriores. La configuración de cada cliente en un solo lugar: Agentes y asistentes de IA.

Elige el que coincida con tu apetito de riesgo

1. Llama a la API desde tu backend

Tu servidor llama al nuestro, tu interfaz renderiza el resultado. Mantienes control total de la relación con el cliente y nunca vemos tu patrón de tráfico ni a tu cliente. Esto es lo que elegiríamos. Las llamadas de origen cruzado desde un navegador están restringidas a nuestra propia consola, así que este patrón es servidor a servidor por diseño.

2. Enlaza a la consola alojada

Apunta a un cliente a la consola de demostración para configurar la cobertura y devuelve la referencia de la cotización a tu flujo. Lo más rápido de implementar, y el menor control: la página es nuestra, así que su apariencia y texto cambian cuando los nuestros cambian.

3. Ejecuta todo tú mismo

Tres archivos y una tabla. Despliega el motor en tu propia cuenta de Cloudflare, apúntalo a tu propia base de datos, y ya no estamos en el camino en absoluto. El código fuente no es público hoy, así que esto comienza pidiéndolo. Cubierto en Ejecútalo tú mismo abajo.

Pregúntale al motor qué cobra

No codifiques la lista de precios. GET /api/v1/verticals publica cada vertical, su capa base obligatoria y sus módulos opcionales, con los precios que el motor realmente aplicará. Construye tu interfaz desde esa respuesta y un cambio de precio nunca desincroniza tu pago de la cotización.

const { verticals } = await (await fetch(BASE + '/api/v1/verticals')).json();

for (const v of verticals) {
  renderTab(v.key, v.label, v.description);
  renderLocked(v.base);              // mandatory, always on
  v.addons.forEach(renderToggle);    // optional modules
}

Si debes almacenarlo en caché, hazlo con una expiración y vuelve a verificar al cargar. Nuestra propia consola mantiene una copia incrustada para el primer renderizado y se hidrata desde este endpoint de inmediato, y una prueba falla la compilación si los dos alguna vez discrepan.

Maneja estos seis antes de lanzar

Cada uno ha quemado una integración real en algún lugar. Son baratos de manejar ahora y caros de descubrir en una auditoría.

Qué ocurreQué hacer
Llega un 200 pero no se escribió ningún registro de auditoría No enviaste ninguna clave, o el libro de contabilidad estuvo brevemente inaccesible.Lee persistence.persisted. Muestra el precio, pero nunca digas a un cliente que su cotización está archivada a menos que esté literalmente en true. persistence.attempted distingue las dos causas.
El cliente alterna rápidamente Las respuestas llegan fuera de orden y un precio obsoleto aterriza al final.Etiqueta cada solicitud con un número incremental e ignora cualquier respuesta más antigua que la más reciente que hayas mostrado. Aborta la solicitud anterior.
Envías un componente que no cotizamos Tu compilación está por delante de la nuestra, o por detrás.Comprueba ignored_components en cada respuesta. Nunca está vacío por accidente, así que trata cualquier cosa en él como un desajuste de despliegue y alerta sobre ello.
Llega un 401 donde antes había un 200 Tu clave fue revocada, o tu distribuidor fue suspendido.Trátalo como una interrupción, no como un error de validación, y avisa a alguien. No elimines la clave y reintentes: eso convierte un fallo ruidoso en uno silencioso, y cada cotización posterior desaparece de tu rastro de auditoría.
El motor no responde Fallo de red o tiempo de espera agotado.Establece un tiempo de espera de cliente de unos pocos segundos. No recurras a un precio calculado localmente: mostrar un número que no produjimos es cómo un cliente recibe una cotización que no puedes honrar.
Reintentas una cotización registrada después de un tiempo de espera El primer intento puede haberse escrito antes de que la conexión se cayera.Envía un encabezado Idempotency-Key — tu propia referencia de pedido o sesión funciona — y reutilízalo en cada reintento de esa cotización. La misma clave registra como máximo una entrada, y un reintento obtiene esa entrada de vuelta con persistence.replayed: true. Sin él, un reintento puede dejar una segunda entrada permanente en un libro de solo añadido que dice que la cotización se dio dos veces. La misma clave para una cotización diferente se rechaza con 409; usa una clave nueva para una cotización nueva.

Lo que el motor rechaza

LímiteValorAl incumplirse
Cuerpo de la solicitud16 KB413 PAYLOAD_TOO_LARGE
Tiempo de espera de escritura en el libro5 sLa cotización aún se devuelve, marcada como no persistida
Escrituras en el libro, todos los llamadores120 / minLa cotización aún se devuelve, marcada como no persistida
Orígenes del navegadorsolo consolaBloqueado por el navegador, no por nosotros

El techo de escritura se comparte deliberadamente en lugar de ser por llamador. El libro rechaza la eliminación, así que una inundación sería daño permanente, y un límite que un llamador no puede eludir conversando vale más que uno generoso que sí puede.

Ejecútalo tú mismo

La plataforma son tres archivos: un esquema SQL, un Cloudflare Worker y una consola de una sola página. No hay tiempo de ejecución propietario ni nada que llame a casa. Montar tu propia copia toma unos diez minutos una vez que tienes el código fuente. Ese código está hoy en un repositorio privado (el verificador, los grabadores y los kits son lo que está publicado), así que pídenoslo; si ejecutarlo sin nosotros es una condición de tu piloto, acuerda cómo lo obtendrías antes de que comience el piloto. Consulta el plan de continuidad y salida.

# 1. Create the audit ledger in your own Postgres or Supabase project
psql -f schema.sql

# 2. Point the engine at it and deploy to your own Cloudflare account
wrangler secret put SUPABASE_SERVICE_ROLE_KEY
wrangler deploy

# 3. Publish the console
npm run deploy:console

La matriz de calificación vive en un objeto congelado en la parte superior del Worker. Cambia un precio allí, ejecuta las pruebas, despliega. El conjunto de pruebas recalcula cada prima desde la matriz y falla si la consola o la documentación no están de acuerdo con ella.

Preferimos que puedas irte a que estés encerrado. Una integración de la que puedas alejarte es una a la que puedas comprometerte.

Lo que aportas

RiskRouter es infraestructura. No convierte a nadie en distribuidor de seguros, y no puede sustituir las cosas que un regulador espera que tengas.

  • Tu propio registro FSMA, o el equivalente en tu estado miembro
  • Una aseguradora o grupo de suscripción dispuesto a respaldar la cobertura
  • Tu propio proceso de aprobación de productos y de demanda y necesidades bajo la IDD
  • Tus propios términos orientados al cliente y los documentos de póliza que los acompañan

Nosotros suministramos el enrutamiento, la determinismo de precios y el rastro de auditoría. La posición regulatoria explica dónde está el límite y por qué se dibuja allí.