# RiskRouter: every page, as text > Built from the site itself on 2026-10-01. The short map is https://riskrouter.eu/llms.txt. ## RiskRouter: tamper-evident proof of insurance advice URL: https://riskrouter.eu/ For licensed insurance distributors and the software they run on The law already asks for the record. The first time it is disputed, you will have to show it was never changed. IDD Article 20 says a distributor must be able to justify what it recommended. Any system that stores those records can also edit them, so a supervisor cannot tell an accurate history from a corrected one. RiskRouter seals each record into a log in which changing one entry breaks every entry after it: the fingerprint of an advice note, which never leaves your system, or a quote priced on our server. A report from a vendor’s own system is the vendor’s word. This is a record you can check without us. What each law asks you to record You integrate it into your own product. We never touch your customer, never handle a claim and never hold the carrier relationship. If we stopped existing tomorrow, an export you have already downloaded would still verify without us. Get a sandbox key Watch a changed record get caught The ledger right now: entries chained, head , . Check it yourself The last three entries of the live ledger as signed on 13 September 2026 and timestamped in Bitcoin block 967830. Each entry carries the hash of the one before it. #44 urban_rental 7.50 prev 8205f994 965a4c hash 8688a6a0 b50303 #45 mobility 3.50 prev 8688a6a0 b50303 hash c06ca6e2 4ff694 #46 micro_travel 2.50 prev c06ca6e2 4ff694 hash f95974f5 d8c225 Change the premium of #44 and its hash changes, so #45 no longer points at it, and so on to the end. Try it . 13 September 2026 first head anchored 967 830 earliest Bitcoin block none yet independent witnesses Computed from the anchors and witness keys in the repository when this page was built. Why these cannot be faked Who it is for A large insurer absorbs Article 20 in a compliance department. A brokerage of three people absorbs it in evenings and spreadsheets, and hopes the file is still findable in two years. RiskRouter is built for the second case, and for the software vendors who serve hundreds of them: one integration in a broker-management package gives every broker using it a record they can show. What that integration involves . Recorded where it cannot be edited Every record made with a key is appended to a log the database itself refuses to change or delete, for every role, including ours. Each entry carries the hash of the one before it, the head is signed, and the quote ledger’s head is timestamped in Bitcoin. Your customer’s data stays with you For advice notes and other records that hold personal data, you send only a salted fingerprint; the record never leaves your system. A quote holds no personal data at all. How the evidence log works . Priced on the server, if you price with us Post a vertical and a set of options; get back priced line items, a total and the exact state that was recorded. The browser never computes or sends a premium. There is no SDK to install and no session to manage. If we disappear, your evidence does not RiskRouter is run by one person today. You should ask what happens if that stops before you depend on it, and the answer should not rest on our goodwill on the day it matters. Take everything, any time One authenticated call returns your entries in full, the hashes of the chain they sit in and the signed head. No ticket, no notice period, no fee. It verifies with us switched off Two independent verifiers, in JavaScript and Python, check it offline using only their language’s standard library. Heads are timestamped in Bitcoin, so a history rebuilt later would not match. Try it on a real export . Leaving is documented What you keep, what stops and the steps to move are written down in the continuity and exit plan , with the facts a DORA register of information asks for. Decisions worth knowing before you integrate Most of the engineering went into what happens when things fail. A price from a browser is ignored The server computes every premium and discards anything the client sends. If a modified request tries to remove the mandatory base cover, the server puts it back. A write that failed is reported as failed If the ledger cannot record a quote, the response says recorded: false . It never claims a record that does not exist, because that is precisely what an audit looks for. Money is kept in whole cents Premiums are integers until they are formatted once, at the edge of the response. Floating-point euros drift. The ledger limits its own write rate Because nothing can be deleted, a flood would be permanent. The table caps how fast it accepts entries, and that holds even if the API in front of it is bypassed. The rating matrix is published, not described Four sample verticals ship with the validation build. They are worked examples of what the engine can price, not products and not for sale. Your own rates replace them. The live matrix is served at GET /api/v1/verticals , so an interface shows exactly what the engine charges. Vertical What it covers in the examples Base, per month Options mobility E-bike, scooter, car-share and on-demand fleet exposure 2.00 4 digital_nomad Cross-border remote work, client liability and devices 1.50 4 urban_rental Tenant liability, deposit liquidity and connected-home risk 3.50 4 micro_travel Short-haul multimodal transit and seasonal sports 2.50 4 Every change to these prices is versioned and listed with its fingerprint on the changelog . Where this stands today Frankfurt Where records are stored 0 Personal data fields in a quote 1 request To price a configuration Append-only Enforced by the database RiskRouter runs as a validation build. The routing path is real and every number in the demo comes from the live engine, but no cover is placed, no carrier is contracted and no payment is taken. The regulatory position sets out what is and is not in place. Talk about a pilot Read the security answers ## RiskRouter Console URL: https://riskrouter.eu/console RiskRouter Console price a configuration against the live engine Monthly premium 0.00 a month Base 0.00 Options 0.00 Annual 0.00 Run the full route Prices come from the server. This page never calculates a premium and never touches the database. Figures are indicative. No cover is in force. Response Waiting for the first quote. Payload Copy Trace ## Integrate RiskRouter URL: https://riskrouter.eu/integrate Integrate There is no SDK to install and nothing to license. The engine is an HTTP endpoint, the rating matrix is published at another one, and the audit ledger is a single table. Everything below runs against the live validation build right now. Quickstart Get a sandbox key Check your setup Keys and the audit trail Three patterns Rendering the matrix Failure cases Limits Run it yourself What you bring Quickstart Price a configuration in one request No key, no account, no session. Post a vertical and the components the customer switched on. You get a real price. Recording that quote in the audit ledger is a separate decision, and it is the one that needs a key — take a sandbox key now , or read Keys and the audit trail first. 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 } }' You get back priced line items, a total, the normalised component state the engine used, and a separate report of whether an audit write was attempted and whether it landed. From a Node backend 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; From 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 Get a sandbox key Record, export and verify in five minutes, without writing to anyone A sandbox key records quotes in the real ledger, exactly like a key we issue by hand. You get it on this page, once. We ask for nothing about you and store nothing about you: no account, no email, no name. Only a SHA-256 digest of the key is kept. I understand that entries I record with this key are written to an append-only ledger and can never be deleted , by me or by RiskRouter. Leave this field empty Get a sandbox key Sandbox only 50 recorded entries per key per day limits are enforced by the database, not by this page. A production key is issued by a person, after a conversation. Your sandbox key — copy it now Copy key It is shown once and cannot be recovered, because we only keep its digest. Lost it? Take another. Want a person to look at your use case? Write to us and quote the prefix — it is how we find your sandbox without you sending the key. Check your setup Is your key recording, and does your evidence check out? Paste a key and this page asks the API for your export, then checks it here: that the key is recognised, how many entries it has recorded, that the chain links up to the published head, and that we signed that head. The key is sent only to api.riskrouter.eu , is not stored, and is gone when you leave the page. Your key Check my setup Keys and the audit trail Pricing is open. Recording is attributed. The ledger is tamper-evident: every entry seals the one before it. That is what makes it worth anything to an auditor, and it is also why the write path cannot be open. An entry written by nobody in particular is sealed in permanently, and removing it later would break every digest after it. So the engine treats three cases differently, and the third one is the point. You send You get Ledger No key A real price, immediately Nothing written. attribution.mode is ANONYMOUS A valid key A real price Recorded against your distributor, inside the hash chain An invalid, revoked or suspended key HTTP 401, no price Nothing written A bad key is refused outright and never quietly downgraded to an anonymous quote. The alternative looks friendlier and is far worse: a distributor whose key was mistyped or revoked would keep getting 200s for months, believing they were building an audit trail, and would find out during the audit that nothing had been written. Loud now beats silent then. 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 We store the SHA-256 of your key, never the key. That means we cannot show it to you again, cannot email it to you, and cannot recover it if you lose it — we can only revoke it and issue another. It also means a breach of our database does not hand anyone the ability to write to your audit trail. Keys are per environment. A sandbox key and a production key are separate rows and separate digests, so a test quote can never land in a production ledger by accident. Getting your evidence back out The same key exports it. This is the endpoint to wire into a monthly job on day one, not the day you need it. curl -s -H "Authorization: Bearer $RISKROUTER_API_KEY" \ https://api.riskrouter.eu/api/v1/ledger/export > "ledger-$(date +%F).json" You get your entries in full, the digest skeleton of the whole chain they sit inside, and the signed attestation for the head. Two standard-library Node scripts check all three, offline, with no key of ours and no call to us — clone github.com/aniljangrabe-dev/riskrouter-verify , a separate, public repository that shares no code with this one: 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 Keep them. An export you downloaded last year still verifies after we have stopped answering the phone, which is the only honest answer to what happens to my audit trail if you go under . It is also why there is no SDK and nothing to license: a product that is hard to leave is a product that has to be, and we would rather not need that. Integration kit Working code in the language your product is written in Each example prices a quote, records it with an idempotency key and retries without recording twice, records a salted fingerprint of a demands-and-needs note, exports the evidence and proves one entry. Standard library only, no SDK to install, and every one is run on every change against the real engine, with its output checked by two independent verifiers. Python : riskrouter.py , signer.py (sign your own claims), demo.py PHP : RiskRouter.php , demo.php C# (.NET 8) : RiskRouter.cs , Program.cs , RiskRouterDemo.csproj Java : RiskRouterDemo.java Reference app : app.py , a one-file broker desk that keeps the customer’s note on your side and produces an evidence pack an inspector can check offline with check_pack.py . Verifier : riskrouter_verify.py , standard-library Python, independent of everything else here. How to use the kit: README . Drop-in recorders Evidence from where your decisions are already logged If your system already logs its decisions, through Python’s logging , through OpenTelemetry spans, or through a function that returns a decision, a recorder turns that into evidence without an integration project. It canonicalises each record, salts it and keeps it, with its salt, in a journal on your side; only the digest and the kind are sent, in batches, to this log, to your own instance, or to none. A record is written to the journal before its digest is sent, so an outage never loses one, and it is marked recorded only when the log says so. No dependencies, and never a condition of using the 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+, standard library): riskrouter_recorder , with a logging handler, a decorator and an OpenTelemetry span processor, and agents.py . README Node (20+, no dependencies): recorder.mjs , with withEvidence and an OpenTelemetry span processor; agents.mjs and mcp-server.mjs . README AI agents. The same packages carry adapters for the frameworks agents are built with: a callback handler for LangChain and LangGraph (Python and JavaScript) and a tracing processor for the OpenAI Agents SDK (both languages). Each agent run becomes one record, with its tool calls, model calls, handoffs, guardrails and graph nodes as steps; each step keeps a SHA-256 of the text it handled, not the text. An MCP server gives any MCP client a record_decision tool; what it records is the agent’s own statement, and says so. # 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) gives you the record, its salt and the proof, which a supervisor checks offline with either verifier. Both recorders are tested on every change against the real engine and the real OpenTelemetry, LangChain, OpenAI Agents and MCP SDKs. They are licensed Apache-2.0 (the recorders only). Until they are on PyPI and npm, copy them from here. Security logs. logseal.mjs seals any log stream ( journalctl , tail -F , a syslog relay) segment by segment, so after an incident you can show that no sealed segment was changed or removed. The segments stay in your own archive. Sealed security logs AI agents Connect an AI agent over MCP The evidence log speaks the Model Context Protocol, so an AI assistant or agent framework can read the log, fetch proofs and record digests without anyone writing an integration. Add this server to any MCP client: https://api.riskrouter.eu/mcp { "mcpServers": { "riskrouter": { "type": "http", "url": "https://api.riskrouter.eu/mcp", "headers": { "Authorization": "Bearer " } } } } Reading needs no key. record_evidence takes the SHA-256 of a record you keep and a short kind, never the record, and needs your key; a sandbox key takes a minute. Each tool is the same route as in the API reference , with the same checks. There is no pricing tool. To record from inside the agent’s own process instead, with the record kept in your journal, use the local MCP server and the framework adapters above. Every client’s setup in one place: AI agents and assistants . Three patterns Pick the one that matches your risk appetite 1. Call the API from your backend Your server calls ours, your interface renders the result. You keep full control of the customer relationship and we never see your traffic pattern or your customer. This is what we would choose. Cross-origin calls from a browser are restricted to our own console, so this pattern is server-to-server by design. 2. Link out to the hosted console Point a customer at the demo console to configure cover and hand the quote reference back to your flow. The fastest thing to stand up, and the least control: the page is ours, so its appearance and copy change when ours do. 3. Run the whole thing yourself Three files and one table. Deploy the engine to your own Cloudflare account, point it at your own database, and we are no longer in the path at all. The source is not public today, so this starts with asking us for it. Covered in Run it yourself below. Rendering Ask the engine what it charges Do not hardcode the price list. GET /api/v1/verticals publishes every vertical, its mandatory base layer and its optional modules, with the prices the engine will actually apply. Build your interface from that response and a price change never desynchronises your checkout from the quote. 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 } If you must cache it, cache it with an expiry and re-check on load. Our own console keeps an embedded copy for the first paint and hydrates from this endpoint immediately, and a test fails the build if the two ever disagree. Failure cases Handle these six before you ship Each one has burned a real integration somewhere. They are cheap to handle now and expensive to discover in an audit. What happens What to do A 200 comes back but no audit record was written You sent no key, or the ledger was briefly unreachable. Read persistence.persisted . Show the price, but never tell a customer their quote is on file unless it is literally true . persistence.attempted tells the two causes apart. The customer toggles quickly Replies arrive out of order and a stale price lands last. Tag each request with an incrementing number and ignore any reply older than the newest one you have rendered. Abort the previous request. You send a component we do not price Your build is ahead of ours, or behind it. Check ignored_components on every response. It is never empty by accident, so treat anything in it as a deployment mismatch and alert on it. A 401 comes back where a 200 used to Your key was revoked, or your distributor was suspended. Treat it as an outage, not as a validation error, and page someone. Do not strip the key and retry: that turns a loud failure into a silent one, and every quote after it disappears from your audit trail. The engine does not answer Network fault or timeout. Set a client timeout of a few seconds. Do not fall back to a locally computed price: showing a number we did not produce is how a customer gets quoted something you cannot honour. You retry a recorded quote after a timeout The first attempt may have been written before the connection dropped. Send an Idempotency-Key header — your own order or session reference works — and reuse it on every retry of that quote. The same key records at most one entry, and a retry gets that entry back with persistence.replayed: true . Without it, a retry can leave a second, permanent entry in an append-only ledger that says the quote was given twice. The same key for a different quote is refused with 409; use a new key for a new quote. Limits What the engine refuses Limit Value On breach Request body 16 KB 413 PAYLOAD_TOO_LARGE Ledger write timeout 5 s Quote still returns, marked not persisted Ledger writes, all callers 120 / min Quote still returns, marked not persisted Browser origins console only Blocked by the browser, not by us The write ceiling is deliberately shared rather than per-caller. The ledger refuses deletion, so a flood would be permanent damage, and a cap that one caller cannot talk its way around is worth more than a generous one that can be. No lock-in Run it yourself The platform is three files: a SQL schema, a Cloudflare Worker and a single-page console. There is no proprietary runtime and nothing phones home. Standing up your own copy takes about ten minutes once you have the source. That source is in a private repository today (the verifier, the recorders and the kits are what is published), so ask us for it ; if running it without us is a condition of your pilot, agree how you would get it before the pilot starts. See the continuity and exit plan . # 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 The rating matrix lives in one frozen object at the top of the Worker. Change a price there, run the tests, deploy. The test suite recomputes every premium from the matrix and fails if the console or the documentation disagrees with it. We would rather you could leave than have you locked in. An integration you can walk away from is one you can commit to. Before a pilot What you bring RiskRouter is infrastructure. It does not make anyone an insurance distributor, and it cannot stand in for the things a regulator expects you to hold. Your own FSMA registration, or the equivalent in your member state A carrier or underwriting pool willing to stand behind the cover Your own product approval and demand-and-needs process under the IDD Your own customer-facing terms, and the policy documents that go with them We supply the routing, the pricing determinism and the audit trail. The regulatory position explains where the boundary sits and why it is drawn there. Start a pilot conversation Full API reference ## API reference · RiskRouter URL: https://riskrouter.eu/docs API reference Every endpoint, and no personal data in anything the API stores. Pricing needs no authentication; recording a quote in the audit ledger needs a key, and you can get a sandbox key right now. The server prices every quote and discards any price a client sends. Base URL https://api.riskrouter.eu Machine-readable: openapi.json (OpenAPI 3.1). Point your client generator or coding assistant at it; a test in the repository keeps it identical to the routes the Worker actually answers. Or import riskrouter.postman_collection.json into Postman, Insomnia, Bruno or Hoppscotch. It is generated from the same spec on every build. Its first request takes a sandbox key and stores it, so everything after it works without copying anything; the recording request sends a fresh Idempotency-Key each time. Or skip the tooling and try it on this page , or start from working code in Python, PHP, C# or Java in the integration kit . Browsers may call this API only from the console origin. Server-to-server callers are unaffected, because the browser enforces that rule rather than the API. Try it here Real requests to api.riskrouter.eu , sent from this page. Pricing needs no key. To record, paste a sandbox key ( take one in a few seconds ); it stays in this tab’s memory, is sent only to our API, and is gone when you close the tab. Anything you record is permanent, so record test configurations, never personal data. Request POST /api/v1/quote, no key (priced, not recorded) POST /api/v1/quote, with your key (recorded, idempotent) GET /api/v1/verticals GET /api/v1/ledger/attestation GET /api/v1/ledger/export, with your key Sandbox key Body { "active_vertical": "mobility", "selected_components": { "commuter_roadside": true } } Send POST /api/v1/quote Prices a configuration, and appends an audit record when a distributor key is presented. The only endpoint that writes to the ledger. Authentication Optional, and what it changes is whether the quote is recorded rather than whether it is priced. The ledger is tamper-evident, so an entry cannot be cleaned up later without breaking every digest after it. That is why writes are attributed and reads of the price are not. Header Response Ledger Absent 200 with a real price Nothing written. attribution.mode is ANONYMOUS Authorization: Bearer 200 with a real price Recorded against that distributor, inside the hash chain A key that does not resolve 401 INVALID_API_KEY Nothing written An unresolvable key is refused rather than downgraded to an anonymous quote. Downgrading would let a distributor with a mistyped or revoked key collect 200s for months and discover at audit that nothing had been recorded. We store only the SHA-256 of a key, so a lost key can be revoked and replaced but never recovered. Retries: Idempotency-Key Optional, and worth sending on every recorded quote. The same key from the same distributor records at most one ledger entry, ever; a retry with it gets that entry back with persistence.replayed: true and an Idempotent-Replayed: true header, and nothing new is written. The check and the write happen in one database transaction, so two retries racing each other still produce one entry. Use 1 255 visible ASCII characters with no spaces; your own order or session reference is ideal. Only its SHA-256 is stored, never the key, so nothing you put in it can end up in a table that is never deleted; a random UUID is still the better habit. Reusing a key for a different quote is refused with 409 IDEMPOTENCY_KEY_REUSED and records nothing. Different means different in what would be recorded — vertical, components the engine actually priced, premium — so a retry that adds a component the engine ignores is still the same request. On an anonymous quote the header is ignored, because nothing is written. Request Send active_vertical as one of the four keys below. selected_components is optional; leave it out to price the base layer alone. Only an explicit true enables a component, so the string "false" selects nothing. 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 } }' Response selected_components comes back normalised to what was actually sold. The mandatory base layer is always present and always true. Anything the engine did not recognise appears in ignored_components , so a client that has drifted out of step shows up in testing. { "ok": true, "quote": { "quote_reference": "…", "active_vertical": "urban_rental", "currency": "EUR", "billing_interval": "MONTHLY", "selected_components": { "tenant_fire_water": true, … }, "ignored_components": [], "line_items": [ … ], "totals": { "base_layer_premium": "3.50", "add_on_premium": "6.00", "total_monthly_premium": "9.50", "indicative_annual_premium": "114.00", "active_add_on_count": 2 } }, "compliance": { "status": "MOCK_ROUTING_VERIFIED", "binding_state": "NOT_BOUND. Indicative simulation only, …" }, "persistence": { "attempted": true, "persisted": true, "record_id": "…", "latency_ms": 41 }, "attribution": { "recorded": true, "mode": "ATTRIBUTED", "distributor": "…", "environment": "sandbox" } } Reading persistence A 200 does not prove an audit record exists. The write is reported separately, and a failed write degrades the response instead of failing it, because a ledger fault should not take pricing down with it. Treat a record as stored only when persistence.persisted is literally true . persistence.attempted separates the two reasons it can be false: no key was sent, or the write was tried and did not confirm. The first is a configuration choice, the second is an incident. POST /api/v1/sandbox/keys Issues a sandbox key on the spot, with no account and no one to write to first. The key records quotes in the ledger exactly like one we issue by hand, so the whole evaluation — price, record, export, verify — can be done in a few minutes. Or use the form on the integration page , which calls this for you. curl -s -X POST https://api.riskrouter.eu/api/v1/sandbox/keys \ -H "Content-Type: application/json" \ -d '{"acknowledge_permanent": true}' acknowledge_permanent is required and must be the boolean true . Entries you record are written to an append-only ledger and can never be deleted, and you should not find that out afterwards. Nothing else is read from the body: no name, no email, nothing about you is stored. The response carries the key once, its prefix, and runnable next steps with the key already in them. Only a SHA-256 digest of the key is kept, so a lost key cannot be recovered — ask for another. Limits are enforced by the database itself: 50 recorded entries per key per day, and a shared allowance of new keys per hour. Sandbox only; a production key is issued by a person. GET /api/v1/verticals Publishes the rating matrix, so a client renders exactly what the engine prices instead of carrying a copy that can drift. The console loads this on startup. GET /api/v1/ledger/attestation The entry count, the head hash, and the canonical form the digest is computed over. Record the head with a date and any later history that does not reproduce it has been altered. Nothing about any customer is exposed: the attestation commits to the ledger without disclosing it. GET /api/v1/ledger/export Your own entries in full, plus (chain_index, row_hash, prev_hash) for every entry in the ledger, plus the signed attestation. Requires your API key: an export is scoped to one distributor, and an anonymous caller has nothing to export. Together those three pieces let you rebuild each of your digests from its own content and follow the chain to the head we signed — with no credential of ours and no call to us at verification time. The skeleton carries digests only, never another distributor’s content. curl -s -H "Authorization: Bearer $RISKROUTER_API_KEY" \ https://api.riskrouter.eu/api/v1/ledger/export > export.json node tools/verify-attestation.mjs export.json # we signed this head node tools/verify-ledger.mjs export.json # your entries produce it A ledger with more than 25 000 entries is refused with LEDGER_TOO_LARGE rather than truncated. A partial skeleton cannot reach the head, so it would verify as broken and send you hunting for tampering that never happened. Rate limited twice, because two different people abuse it. By address before your key is resolved, so a stranger cannot spend a database round trip per request just by asking; then six a minute per distributor, keyed to you rather than to your address. An export is a periodic record, not a polling endpoint — take one a month and keep it. One export proves consistency. Several, saved months apart, prove history — see verify for why that distinction is the whole point. GET /api/v1/ledger/pubkey The public half of the attestation signing key, and its key id. Useful for a quick check, but not the copy to trust: verifying a signature against a key we hand you at the moment you verify proves nothing if we are the thing in question. The copy that counts is anchors/signing-key.json in the public repository, which stays there across rotations so an attestation saved years ago is still checkable. POST /api/v1/contact Serves this site’s own contact form. It is listed because an undocumented public write endpoint is a thing an auditor is right to ask about, not because it is part of the integration surface — there is no reason to call it from your own code. It writes to contact_enquiries , which unlike the ledger is deletable by design: it holds personal data and must stay erasable under GDPR Article 17. The data protection page sets out what is kept and for how long. POST /api/v1/landings Counts one arrival from a tagged campaign link, for this site’s own measurement; there is no reason to call it from an integration. The body is {"src": "linkedin-sept", "path": "/integrate"} and nothing else is read or stored: no IP address, no identifier, no browser details. The result is a daily count per campaign and page, described on the data protection page . Anyone can inflate a count, so the numbers are marketing signals, never evidence. Answers 204. v2 Evidence log POST /api/v2/evidence Record that any regulated decision existed, without sending it: a suitability assessment, a credit decision, an AI system’s log line, a quote. You hash your own record and send only the digest; we never see the record, so it may contain whatever your own obligations require. Needs your key. Entries are leaves of an RFC 6962 Merkle tree, so one entry is proven against a signed head with a handful of hashes, and nothing about any other entry is revealed. The format is in the open specification . # Salt the record, or anyone who can guess it can confirm it from the digest. SALT=$(openssl rand -hex 16) DIGEST=$( (printf '%s' "$SALT"; cat decision.json) | sha256sum | cut -d' ' -f1) curl -s -X POST https://api.riskrouter.eu/api/v2/evidence \ -H "Authorization: Bearer $RISKROUTER_API_KEY" -H "Content-Type: application/json" \ -d "{\"record_digest\":\"$DIGEST\",\"kind\":\"ai.decision\"}" Two fields only: record_digest (lowercase hex SHA-256) and kind (a tag you choose: a z, 0 9, dots and hyphens, at most 40, such as mifid.suitability ). Anything else is refused, never coerced. The answer is 201 with the entry ( leaf_index , created_at , leaf_hash ) and recorded: true ; a refused write answers 503 with recorded: false , never a success. Keep your record, your salt and the entry: without your record nobody, including us, can show what it said. Not sure what to put in the record? The regime packs say, for IDD, MiFID II, the AI Act, GDPR Article 22 and DORA, which fields to record and which article each one speaks to, with a canonical form so someone else can re-hash your record exactly. Optionally, sign the claim yourself. Send signer_key_id , claimed_at (your own timestamp, YYYY-MM-DDTHH:MM:SS.ffffffZ ) and client_signature (ECDSA P-256 over riskrouter-evidence-claim|v3|kind|record_digest|signer_key_id|claimed_at , raw r || s in base64) with the two fields above, all three or none. The signature is verified against a key you registered before anything is written, and then sits inside the leaf: a v3 leaf, whose proof shows that you asserted the decision, not only that we sealed it. A signature that does not verify records nothing. The specification has the exact forms; the Python kit has a standard-library signer. POST /api/v2/evidence/keys Register the public half of the key you sign claims with, once: public_key as a P-256 JWK ( {"kty":"EC","crv":"P-256","x":"…","y":"…"} ). Needs your key. Answers 201 with the key_id (the first 16 hex characters of SHA-256 over the JSON array [x, y] ) or 200 if that key was already yours. A key id belongs to one distributor forever, so another distributor’s key answers 409 . Keys are never removed: leaves signed before you rotate stay verifiable. Publish the same key somewhere you control, so a verifier need not take our word for whose it is. GET /api/v2/evidence/keys ?key_id=… . The registered public key under that id, for anyone: a public key is public, and a verifier of a v3 leaf needs it. Answers the key and when it was registered, never whose it is. POST /api/v2/evidence/batch Many digests in one request: entries , an array of 1 to 500 objects each with record_digest and kind , recorded in the order sent, in one transaction. The same checks apply to each entry as to a single record, and the same ceilings hold per row: if any entry is refused, nothing in the batch is written and the answer says so. The body may be up to 128 KB. Answers 201 with every entry and its leaf index. GET /api/v2/evidence/head The signed tree head: tree_size , root_hash and timestamp , signed over riskrouter-evidence-head|v2|tree_size|root_hash|timestamp with the same key as the v1 attestation. Unsigned heads say so. Save one; every later head must be consistent with it. GET /api/v2/evidence/proof ?leaf_index=N , optionally &tree_size=M . The inclusion proof for one of your entries (needs your key; another distributor’s entry answers exactly like a missing one): the entry, the audit path, and the signed head when tree_size is the current size. To prove against a head you saved earlier, pass its tree_size and check against its root. Take the size and the root from the same signed head. For a signed (v3) leaf the proof also carries signer_public_key , so the client signature can be checked without another request. GET /api/v2/evidence/consistency ?first=M , optionally &second=N . Proof that the tree you saved at size M is a prefix of the tree at size N : the check that catches a rewritten history. Public, because it reveals nothing but hashes. Check it against the root in the head you saved, never a root we supply. This is what an independent witness runs. POST /api/v2/evidence/statement Register a SCITT Signed Statement (body application/cose , your key). It must be a hash envelope: a COSE_Sign1 signed ES256 with a key you registered (its id as kid ), with CWT claims iss and sub and a payload that is the 32-byte SHA-256 of your artifact, so the artifact never comes here. The log keeps one leaf holding the statement’s digest, and answers with an RFC 9942 COSE Receipt and the Transparent Statement, both base64. The profile is in the specification . GET /api/v2/evidence/receipt ?leaf_index=N , with the key that recorded the entry: a COSE Receipt of inclusion for it at the current tree size ( application/scitt-receipt+cose ), for a statement or any other entry. Answered only when the signing key is bound; otherwise 503 RECEIPT_NOT_SIGNED . GET /tlog/evidence-v2/checkpoint The same tree as /api/v2/evidence/head , as a C2SP checkpoint ( text/plain ): a signed note of three lines, the origin api.riskrouter.eu/tlog/evidence-v2 , the tree size and the root in base64, signed with the log's Ed25519 key. This is the form the public witness network cosigns. Answered only when that key is bound and matches the published one; otherwise 503 CHECKPOINT_NOT_SIGNED , never an unsigned note. Format and key in the specification . GET /tlog/evidence-v2/tile//[.p/] The tree as tiles of 256 hashes, exactly as c2sp.org/tlog-tiles lays them out, so anyone can mirror the whole tree and compute any root or proof without this API. Immutable once served. Only hashes are published: entry bundles ( tile/entries/… ) answer 404 ENTRY_BUNDLES_NOT_PUBLISHED , because every leaf names a distributor and a kind. node tools/checkpoint.mjs mirror fetches every tile and checks it gives the checkpoint's root. POST /mcp The evidence log for AI agents, over the Model Context Protocol (Streamable HTTP, stateless: one JSON-RPC message per request, one JSON answer, no session). Point any MCP client at https://api.riskrouter.eu/mcp . Tools: get_evidence_head , get_inclusion_proof , get_consistency_proof , get_checkpoint , get_ledger_attestation , get_usage and record_evidence . Each is the route above it on this page, answered by the same code with the same errors. Reading needs no key; record_evidence takes a digest and a kind, never a record, and needs your key in the connection's Authorization header. There is no pricing tool: the engine prices for licensed distributors' software, not for an agent talking to the public. Connecting a client . GET /api/v1/usage How much is recorded, and by whom, as counts: entries in the quote ledger and the evidence log, the last 7 and 28 days, twelve calendar weeks, and the figure that matters, outside : entries recorded with keys that are not ours, self-serve sandbox keys counted separately. Public, because it returns nothing but numbers and week dates; no identifier, no premium, no record. Cached for five minutes at the edge. /usage shows it. GET /api/v1/health Liveness, plus whether the audit ledger binding resolved. binding_configured: false means quotes still price but nothing is recorded. The bare domain answers this too. Errors Every error carries the same envelope: ok: false and an error object with a stable code , a message , and a docs link to its row in this table. Code HTTP Cause UNKNOWN_VERTICAL 400 Missing or unrecognised active_vertical INVALID_COMPONENTS 400 selected_components was an array rather than an object INVALID_PAYLOAD 400 Body was not a JSON object MALFORMED_JSON 400 Body was not valid JSON INVALID_API_KEY 401 Key is unknown, revoked, or its distributor is suspended. Nothing was recorded KEY_CHECK_UNAVAILABLE 503 A key was sent but could not be checked. Refused rather than priced unrecorded NOT_AUTHENTICATED 401 An export was requested with no key. There is nothing to export for nobody in particular LEDGER_TOO_LARGE 413 The ledger is past the single-response export ceiling. Refused rather than truncated into a proof that fails UNSUPPORTED_MEDIA_TYPE 415 Content type was not application/json PAYLOAD_TOO_LARGE 413 Body exceeded 16 KB INVALID_IDEMPOTENCY_KEY 400 Idempotency-Key was empty, too long, or not visible ASCII IDEMPOTENCY_KEY_REUSED 409 That key already recorded a different quote; nothing was written ACKNOWLEDGEMENT_REQUIRED 400 A sandbox key was requested without "acknowledge_permanent": true SANDBOX_CAPACITY_REACHED 429 This hour's allowance of new sandbox keys is used; nothing was issued SANDBOX_NOT_OFFERED 404 A self-hosted instance whose operator has not switched on self-serve sandbox keys; ask the operator for a key. riskrouter.eu always offers them SANDBOX_NOT_ISSUED 503 The key could not be stored, so none was handed over METHOD_NOT_ALLOWED 405 Wrong verb for the route ROUTE_NOT_FOUND 404 No route bound to that path BAD_REQUEST 400 The request URL could not be parsed BODY_READ_FAILED 400 The request body could not be read REQUEST_REFUSED 400 The sign-up form's hidden bot-trap field was filled in; nothing was issued INVALID_ENQUIRY 400 A contact enquiry had fields that need attention; details says which INVALID_LANDING 400 A landing count carried a malformed campaign tag or a path that is not a page on this site RATE_LIMITED 429 Too many requests from one address in a short time. Wait a minute; when a Retry-After header is sent, it says how long ENQUIRY_NOT_STORED 503 The enquiry could not be saved, so it did not reach us. Nothing is reported as sent LANDING_NOT_COUNTED 503 The visit could not be counted; nothing else is affected LEDGER_UNAVAILABLE 502 / 503 The ledger or its attestation could not be read NO_SIGNING_KEY 500 / 503 This Worker publishes no attestation key, or the one bound is unreadable INVALID_EVIDENCE 400 record_digest was not a lowercase SHA-256 hex digest, or kind was not a short tag. Nothing was recorded INVALID_PROOF_REQUEST 400 leaf_index , tree_size , first or second was missing, not a whole number, or outside the tree EVIDENCE_NOT_FOUND 404 No entry at that index was recorded with this key. Another distributor’s entry answers the same EVIDENCE_TREE_TOO_LARGE 413 The evidence log is past the size this route reads in one request. Refused rather than answered with a proof that fails EVIDENCE_CEILING 429 The evidence log is at a ceiling, for this key or overall. Nothing was recorded INVALID_CLIENT_SIGNATURE 400 client_signature does not verify over the claim payload with a key registered to this distributor, or the key id is not one of yours. Nothing was recorded INVALID_SIGNER_KEY 400 public_key was not a P-256 public JWK, or key_id was not a 16-character key id. Nothing was registered SIGNER_KEY_TAKEN 409 That key is registered to another distributor; a key id belongs to one distributor forever. Nothing was registered SIGNER_KEY_NOT_REGISTERED 503 The key could not be stored, so it is not registered SIGNER_KEY_NOT_FOUND 404 No signing key is registered under that id EVIDENCE_NOT_RECORDED 503 The evidence log did not accept the entry. Answered with recorded: false , never as a success INVALID_STATEMENT 400 The Signed Statement breaks the registration policy (the message names the rule). Nothing was recorded INVALID_STATEMENT_SIGNATURE 400 The statement’s signature does not verify with a key registered to this distributor under its kid. Nothing was recorded RECEIPT_NOT_SIGNED 503 No signing key is bound, so no receipt is issued rather than an unsigned one CHECKPOINT_NOT_SIGNED 503 No checkpoint key is bound, or the bound key is not the published one. No checkpoint is served rather than an unsigned one TILE_NOT_FOUND 404 Not a tile path, or a tile the tree does not have yet ENTRY_BUNDLES_NOT_PUBLISHED 404 Only hash tiles are published; a distributor holds its own entries with their proofs TILES_UNAVAILABLE 503 The stored tree cannot be read for that tile ORCHESTRATION_FAILURE 500 Unhandled fault; no detail is leaked Rating matrix All prices are monthly, in euro. Base layers are mandatory and cannot be switched off. Urban Mobility mobility Component code Cover Premium public_liability Public Liability Base €2.00 battery_hardware_theft Battery / Hardware Theft €1.50 commuter_roadside Commuter Roadside Assistance €1.00 commercial_delivery Commercial Delivery Extension €5.00 carshare_deductible Car-Share Deductible Buy-Down €2.50 Digital Nomad & Freelance digital_nomad Component code Cover Premium cyber_extortion_data Cyber-Extortion & Data Protection Base €1.50 high_value_hardware High-Value Hardware Protection €3.00 international_roaming International Roaming Expansion €2.00 professional_indemnity Freelance Professional Indemnity €4.00 contractual_legal Contractual Dispute Legal Protection €1.50 Urban Rental & Housing urban_rental Component code Cover Premium tenant_fire_water Tenant Fire & Water Liability Base €3.50 deposit_liquidity_swap Security Deposit Liquidity Swap €4.00 landlord_legal_defense Landlord Dispute Legal Defense €1.00 roommate_sublet Roommate / Sublet Liability €1.50 smart_home_iot Smart-Home / IoT Failure Cover €2.00 Micro-Travel & Sports micro_travel Component code Cover Premium multimodal_medical_transit Basic Multi-Modal Medical & Transit Base €2.50 winter_sports_gear Premium Winter Sports & Ski Gear €3.50 parametric_delay Parametric Flight / Train Delay €2.00 adventure_sports Extreme Adventure Sports Addendum €3.00 baggage_tech_transit Lost Baggage / High-Value Tech €1.50 ## Worked rate cards by vertical URL: https://riskrouter.eu/solutions Four worked rate cards RiskRouter prices whatever risk vertical you configure into it. The validation build ships with four worked examples — not products, not cover, and not for sale to anyone — so a reader can see exactly what the engine does before pointing it at rates of their own. Each one below is a real base layer and real optional components, priced by the same server that would price yours. mobility E-bike, scooter, car-share and on-demand fleet exposure. base 2.00 / month 5 components See the rate card digital_nomad Cross-border remote work, client liability and device exposure. base 1.50 / month 5 components See the rate card urban_rental Tenant liability, deposit liquidity and connected-home risk. base 3.50 / month 5 components See the rate card micro_travel Short-haul multi-modal transit and seasonal sports exposure. base 2.50 / month 5 components See the rate card Or start from who you are, not what you price The four verticals above are worked examples of pricing. These three are about your role instead. Broker-software vendors Integrate once, and every broker on your package can show what they advised and prove it was not changed afterwards. Distributors, brokers and MGAs Seal the fingerprint of each advice note, and answer Article 20 with a record nobody can edit, including us. Platforms embedding insurance You and your licensed partner bring the cover; RiskRouter prices the configuration and seals the record. The same engine underneath every one of them Nothing below changes from vertical to vertical. The difference between the four pages is the rate card, not the architecture. 01 Priced on the server, always A client sends a vertical and a set of toggles, never a price. The server looks up the mandatory base layer and every selected component from its own matrix and computes the total. A submitted price is not read. 02 Sealed if it is attributed A quote with no key is priced and not recorded. A quote from a resolvable distributor is priced and appended to a chain where changing one entry breaks every entry after it. 03 Yours to configure These four verticals and twenty components are worked examples. Your own base layers, your own components and your own prices replace them; the engine does not change shape. Not sure which one fits Every vertical here is the same shape: one mandatory foundation layer priced into every quote, and four optional modules a customer switches on individually. If what you are pricing does not look like any of the four, say what it is — the question is whether it decomposes into a base layer and optional modules, not whether it matches one of these four labels. Open the live demo Read the integration guide Talk to us ## Urban Mobility rate card URL: https://riskrouter.eu/solutions-mobility Solutions mobility Urban Mobility E-bike, scooter, car-share and on-demand fleet exposure. This is the worked example a micro-mobility operator would configure: one mandatory public-liability layer priced into every session, and four optional modules a rider or a fleet switches on individually. Try it live Integration guide The rate card Exactly what GET /api/v1/verticals returns for mobility today. Your own rates replace these; the shape does not change. Base layer — mandatory Public Liability — €2.00/month. Third-party bodily injury and property damage. Forced on server-side regardless of what a client sends. Optional components Battery / Hardware Theft — €1.50/month. Theft of battery packs, drive units and mounted hardware. Commuter Roadside Assistance — €1.00/month. Recovery and transport home on breakdown during commute. Commercial Delivery Extension — €5.00/month. On-demand fleet and paid-delivery usage extension. Car-Share Deductible Buy-Down — €2.50/month. Buys down the excess payable on shared-vehicle damage claims. Who actually configures this one Read straight off the components above, not a persona invented for this page. 01 Scooter and e-bike operators Public liability priced per session or per subscription, with battery and hardware theft as the add-on that actually matches the loss they see. 02 Car-share platforms The deductible buy-down module exists because a shared-vehicle excess is the friction point at checkout — price it in rather than explain it in a FAQ. 03 On-demand delivery fleets Commercial use voids most personal mobility cover. The delivery extension is a separate, explicit toggle rather than a clause nobody reads. A real request Base layer plus roadside assistance and battery theft: €2.00 + €1.00 + €1.50 = €4.50. No key, no account — recording the quote in the ledger is a separate decision that needs one. curl -X POST https://api.riskrouter.eu/api/v1/quote \ -H 'Content-Type: application/json' \ -d '{ "active_vertical": "mobility", "selected_components": { "commuter_roadside": true, "battery_hardware_theft": true } }' The two selected addons total €2.50, plus the €2.00 mandatory base layer — quote.totals.total_monthly_premium comes back "4.50" , computed server-side, never a value the client sent. Other verticals Digital Nomad Cross-border remote work, client liability and device exposure. Urban Rental & Housing Tenant liability, deposit liquidity and connected-home risk. Micro-Travel & Sports Short-haul multi-modal transit and seasonal sports exposure. All solutions ## Digital Nomad & Freelance rate card URL: https://riskrouter.eu/solutions-digital-nomad Solutions digital nomad Digital Nomad & Freelance Cross-border remote work, client liability and device exposure. The worked example a freelance marketplace or a visa-adjacent platform would configure: one mandatory cyber-extortion layer priced into every quote, and four optional modules a nomad switches on individually. Try it live Integration guide The rate card Exactly what GET /api/v1/verticals returns for digital_nomad today. Your own rates replace these; the shape does not change. Base layer — mandatory Cyber-Extortion & Data Protection — €1.50/month. Ransomware negotiation, data restoration and breach response. Forced on server-side regardless of what a client sends. Optional components High-Value Hardware Protection — €3.00/month. Laptops, cameras and production gear against damage and theft. International Roaming Expansion — €2.00/month. Extends territorial scope beyond the EEA for nomadic stays. Freelance Professional Indemnity — €4.00/month. Client loss arising from professional error or omission. Contractual Dispute Legal Protection — €1.50/month. Legal costs for unpaid invoices and contract disputes. Who actually configures this one Read straight off the components above, not a persona invented for this page. 01 Remote-work and relocation platforms International roaming expansion exists because a nomad visa's territorial scope is the exact question standard travel cover was never built to answer. 02 Freelance marketplaces Professional indemnity priced per contract, per client, rather than a single annual policy a freelancer has to remember to have. 03 Co-working and digital-nomad communities High-value hardware cover for the laptop and camera gear a member's income actually depends on, switched on at sign-up rather than sold separately. A real request Base layer plus international roaming and high-value hardware: €1.50 + €2.00 + €3.00 = €6.50. No key, no account — recording the quote in the ledger is a separate decision that needs one. curl -X POST https://api.riskrouter.eu/api/v1/quote \ -H 'Content-Type: application/json' \ -d '{ "active_vertical": "digital_nomad", "selected_components": { "international_roaming": true, "high_value_hardware": true } }' The two selected addons total €5.00, plus the €1.50 mandatory base layer — quote.totals.total_monthly_premium comes back "6.50" , computed server-side, never a value the client sent. Other verticals Urban Mobility E-bike, scooter, car-share and on-demand fleet exposure. Urban Rental & Housing Tenant liability, deposit liquidity and connected-home risk. Micro-Travel & Sports Short-haul multi-modal transit and seasonal sports exposure. All solutions ## Urban Rental & Housing rate card URL: https://riskrouter.eu/solutions-urban-rental Solutions urban rental Urban Rental & Housing Tenant liability, deposit liquidity and connected-home risk. The worked example a property-management or short-to-mid-term rental platform would configure: one mandatory tenant-liability layer priced into every lease, and four optional modules a tenant switches on individually. Try it live Integration guide The rate card Exactly what GET /api/v1/verticals returns for urban_rental today. Your own rates replace these; the shape does not change. Base layer — mandatory Tenant Fire & Water Liability — €3.50/month. Statutory tenant liability for fire and water damage. Forced on server-side regardless of what a client sends. Optional components Security Deposit Liquidity Swap — €4.00/month. Instant deposit substitution in place of locked-up cash. Landlord Dispute Legal Defense — €1.00/month. Defense fund for disputes over rent, repairs and termination. Roommate / Sublet Liability — €1.50/month. Extends tenant liability to co-tenants and approved sublets. Smart-Home / IoT Failure Cover — €2.00/month. Failure of connected appliances and resulting consequential damage. Who actually configures this one Read straight off the components above, not a persona invented for this page. 01 Property-management platforms Tenant liability priced into onboarding rather than left to a tenant's own home insurance, which frequently does not cover a rented unit correctly. 02 Deposit-alternative fintechs The liquidity swap module is the product itself for a deposit-replacement platform, priced and sealed the same way every other component is. 03 Co-living and flat-share operators Roommate and sublet liability closes the gap standard tenant cover leaves for anyone who is not the named lease-holder. A real request Base layer plus deposit liquidity swap and smart-home cover: €3.50 + €4.00 + €2.00 = €9.50. No key, no account — recording the quote in the ledger is a separate decision that needs one. 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 } }' The two selected addons total €6.00, plus the €3.50 mandatory base layer — quote.totals.total_monthly_premium comes back "9.50" , computed server-side, never a value the client sent. Other verticals Urban Mobility E-bike, scooter, car-share and on-demand fleet exposure. Digital Nomad Cross-border remote work, client liability and device exposure. Micro-Travel & Sports Short-haul multi-modal transit and seasonal sports exposure. All solutions ## Micro-Travel & Sports rate card URL: https://riskrouter.eu/solutions-micro-travel Solutions micro travel Micro-Travel & Sports Short-haul multi-modal transit and seasonal sports exposure. The worked example a booking engine or a train and short-haul flight platform would configure: one mandatory medical and transit layer priced into every trip, and four optional modules a traveller switches on individually. Try it live Integration guide The rate card Exactly what GET /api/v1/verticals returns for micro_travel today. Your own rates replace these; the shape does not change. Base layer — mandatory Basic Multi-Modal Medical & Transit — €2.50/month. Emergency medical and transit disruption cover. Forced on server-side regardless of what a client sends. Optional components Premium Winter Sports & Ski Gear — €3.50/month. Piste liability plus ski and snowboard equipment protection. Parametric Flight / Train Delay — €2.00/month. Automated fixed payout triggered by verified delay thresholds. Extreme Adventure Sports Addendum — €3.00/month. Liability addendum for classified high-risk adventure activity. Lost Baggage / High-Value Tech — €1.50/month. Checked baggage and high-value technology in transit. Who actually configures this one Read straight off the components above, not a persona invented for this page. 01 Train and short-haul flight platforms The parametric delay module is an automated, verifiable payout rather than a claims process nobody at a booking engine wants to run. 02 Ski and winter-sports booking sites Piste liability and gear protection priced into the lift-pass or lesson checkout, not left as a separate policy a guest forgets to buy. 03 Adventure and activity operators The high-risk addendum exists because most standard travel cover excludes exactly the activity a specialist operator sells. A real request Base layer plus winter sports and parametric delay: €2.50 + €3.50 + €2.00 = €8.00. No key, no account — recording the quote in the ledger is a separate decision that needs one. curl -X POST https://api.riskrouter.eu/api/v1/quote \ -H 'Content-Type: application/json' \ -d '{ "active_vertical": "micro_travel", "selected_components": { "winter_sports_gear": true, "parametric_delay": true } }' The two selected addons total €5.50, plus the €2.50 mandatory base layer — quote.totals.total_monthly_premium comes back "8.00" , computed server-side, never a value the client sent. Other verticals Urban Mobility E-bike, scooter, car-share and on-demand fleet exposure. Digital Nomad Cross-border remote work, client liability and device exposure. Urban Rental & Housing Tenant liability, deposit liquidity and connected-home risk. All solutions ## For insurance distributors, brokers and MGAs URL: https://riskrouter.eu/for-distributors For Insurance distributors, brokers and MGAs You already document what a customer needed and justify what you recommended — IDD Article 20 requires it. The question is not whether you keep records. It is whether a record you kept can be told apart from one that was corrected afterwards. In a spreadsheet or a CRM, it cannot. Seal the note’s fingerprint on the day you make the recommendation, and any later change to the note shows. Most brokers will never integrate anything themselves: their broker software would, once, for everyone on it. If that is you, send your vendor this page . Evaluating a system, ours or anyone’s? Start with the twelve-question audit-trail checklist . Get a sandbox key Watch a changed record get caught Where you sit relative to us Money, the customer relationship and the advice note itself stay exactly where they are today. Only a fingerprint reaches us. Your advice the note, made in your own system, as today Your system hashes the note with a salt only you hold and sends us the fingerprint RiskRouter seals the fingerprint into the log and signs the head Your file the note, and proof it has not changed since that day: not by you, not by us, not by anyone with database access The questions your compliance file actually asks Answered directly, not deferred to a call. What data do we send? For an advice note: its salted SHA-256 fingerprint and a short tag such as advice.note . The note, the customer’s name and everything else stay in your system; the fingerprint cannot be turned back into any of them. Does it replace my carriers’ prices? No. Your carriers price their products, as today. What you seal is the record of what you advised. RiskRouter’s own rating engine is optional and prices sample rates ; you do not need it to record evidence. What gets permanently recorded? The fingerprint, its tag, the time and your distributor id, in a log with a signed head. You can prove one record to a supervisor without showing them any other. A priced quote is recorded in full, chained to the entry before it. Where is it hosted? Records are stored in Frankfurt, Germany, inside the EU; requests are processed at Cloudflare’s nearest location, which may be outside the EEA, with nothing stored there. An encrypted daily backup is kept on GitHub for 90 days, outside the EU. The full position is on the privacy page . Can we verify it ourselves? Export your own entries and check them offline with our open-source verifiers, in JavaScript or Python, standard library only, with no call back to us. See how the tamper check works . What if RiskRouter disappears? An export you downloaded last year still verifies after we have stopped answering the phone. That is the actual answer to the actual question, not a promise. How much engineering work is required? If your broker software integrates RiskRouter, none: the note is sealed when you save it. Otherwise, one HTTP call per record and no SDK, with working code in Python, PHP, C#, Java and JavaScript. How do we test it before committing? Take a sandbox key on the integration page , with nobody in the loop. It records in the real log under its own distributor id, so you test the real thing; entries are permanent, and the page asks you to accept that first. If you are an MGA rather than a broker Nothing above changes. The distributor id in the ledger is yours whether you write the recommendation yourself or aggregate it from a panel of agents underneath you — the chain records who was attributed, at the level you issue keys to. What this replaces 01 A spreadsheet nobody can date-stamp A cell that says "reviewed" proves nothing about when, or whether it looked different last month. 02 An argument about which version is real When the note in the file and the one in the CRM disagree, the fingerprint says which one existed on the day. A three-person practice gets the same answer a compliance department would. 03 Trusting the operator's word A database dump is a claim. A chain a holder can verify offline, against a signed head hash, is evidence. Get a sandbox key What your software vendor would do Talk to us ## For platforms embedding insurance URL: https://riskrouter.eu/for-embedded-insurance For Platforms embedding insurance You already know how to run a mobility fleet, a booking flow, a rental platform or a freelance marketplace. What you do not want to build is a compliance-grade audit ledger just to switch on a cover toggle at checkout. RiskRouter is the part you would otherwise have to build yourself: server-side pricing and a tamper-evident record, behind one HTTP call. You bring the cover. Selling insurance at checkout is insurance distribution. Depending on the product it needs your own registration, or a licensed partner who distributes it, and always an insurer who carries the risk. RiskRouter is none of those and places no cover. It prices the configuration against a published rating matrix (today the sample rates, in a pilot yours) and seals the record. Where the rules apply . Open the live demo Integration guide Where you sit relative to us Your checkout sends the configuration RiskRouter API returns the price and a sealed record Your customer sees your price in your checkout We never touch your customer, never handle a claim, never hold the carrier relationship, and never see a name, an email or an account id. You keep all of that. We price a configuration and, if you hold a key, seal the record. The questions an engineer actually asks Answered directly, not deferred to a call. What data do we send? A vertical key and a set of component toggles — { "active_vertical": "mobility", "selected_components": { "commuter_roadside": true } } . Nothing identifying your user. What does RiskRouter calculate? The total premium, server-side, from the published rating matrix. A price your frontend computed is never trusted as the answer. What gets permanently recorded? Nothing, unless you send an API key. A quote with no key is priced and returned; nothing is written. Recording is a separate, attributed decision. Where is it hosted? Records are stored in Frankfurt, Germany, inside the EU. Requests are processed by Cloudflare at the location nearest the caller, which may be outside the EEA, and nothing is stored there. An encrypted daily backup is kept on GitHub for 90 days, outside the EU. A quote carries no personal data either way. Can we verify it ourselves? Export your entries any time and check them offline with our open-source verifiers, in JavaScript or Python, with no call back to us. See the tamper-detection demo . What if RiskRouter disappears? An export you already hold still verifies with us gone. Nothing about your evidence depends on our uptime a year from now. How much engineering work is required? No SDK, no session, no account to provision before you can price: one HTTP call, with working code in Python, PHP, C#, Java and JavaScript, and the failure cases worth handling written down. How do we test it? Price against the live demo with no signup at all, or take a free sandbox key that records in the real ledger under its own distributor id. Its entries are permanent, and the page asks you to accept that first. Pick the vertical closest to what you are building Each is a real, worked rate card — a mandatory base layer plus optional components, not a category label. mobility E-bike, scooter, car-share and on-demand fleet exposure. base 2.00 / month 5 components See the rate card digital_nomad Cross-border remote work, client liability and device exposure. base 1.50 / month 5 components See the rate card urban_rental Tenant liability, deposit liquidity and connected-home risk. base 3.50 / month 5 components See the rate card micro_travel Short-haul multi-modal transit and seasonal sports exposure. base 2.50 / month 5 components See the rate card Building something else? The question is whether it decomposes into a mandatory base layer and optional modules, not whether it matches one of these four labels — tell us what it is . Why not build it yourself 01 You would still need the ledger The hard part of evidence is not the pricing math; it is proving the pricing math was not changed afterwards. That is the harder half, and it is what we actually built. 02 You would own an audit posture, not a feature Append-only triggers, a signed attestation, an offline verifier — each is small alone and easy to get subtly wrong together. We carry that so your team does not have to. 03 Leaving stays trivial, on purpose No SDK, nothing to license. If we are wrong for you in six months, you keep every record and the means to verify it, and you leave without asking anyone's permission. Open the live demo Read the integration guide Talk to us ## Trust and verification URL: https://riskrouter.eu/trust For security, compliance and audit review Don’t trust RiskRouter. Verify it. Every claim below is checkable without asking us anything. That is deliberate: a claim you have to take on faith is not evidence, and an audit trail whose only witness is the vendor who produced it is not one either. See tamper detection live Full regulatory position What we send, what we store, where No personal data in a quote A quote payload is a vertical key and boolean component toggles. There is no field for a name, an email, or an identifier — not omitted by policy, absent from the schema. Server-side pricing, always The server looks up the price from its own matrix. A number a client sends is never read back as the answer, so a manipulated frontend cannot produce a cheaper quote. Stored in Frankfurt, processed at the edge Records are stored by Supabase in eu-central-1 , Frankfurt. A request is processed by Cloudflare at the location nearest the caller, which may be outside the EEA; nothing is stored there. We say it this way because EU-only would need a compute restriction we do not have. One more copy exists: a daily backup, encrypted before it leaves with a key GitHub does not hold, is kept on GitHub for 90 days, which is outside the EU. Detail on the privacy page . What the request path can reach, and what it cannot One destination, mechanically enforced — not a policy someone has to remember. The Worker that prices and seals a quote makes exactly one outbound call: to the Supabase URL from its own binding. Nothing else — no analytics, no third-party API, no carrier, no payment rail. A stranger's request cannot cause this Worker to contact anywhere else, and that property is asserted by an automated test on every change, not merely documented. The separate administrative console adds exactly one more destination for its own use: Cloudflare Access's key endpoint, to verify who is signed in. It cannot price a quote, write to the ledger, or reach the public API at all — it does five things only: create a distributor, suspend or reactivate one, issue a credential, revoke one, and mark a contact enquiry as read or answered. The ledger itself 01 Append-only, structurally A database trigger refuses UPDATE and DELETE on the audit table for every role, including the administrator's own. This is not a permission that could be granted back — the trigger fires regardless of who is asking. 02 Chained, not just logged Every entry's hash depends on the entry before it. Changing one historical value breaks every digest computed after it, which is checkable by recomputing them — not by trusting that nobody would. 03 Signed, not just chained We periodically sign the current head hash with an ECDSA key and publish it. A saved, signed attestation is something we cannot later disown — it proves we asserted this history at this time, independent of whether the chain is later rebuilt. Verifying it yourself, offline A hash chain alone proves history was not edited. It cannot prove history was not rebuilt from scratch — a rebuild recomputes every digest consistently and looks perfect. The signed attestation closes that gap: it is a claim we cannot take back. Export your own entries any time you hold a key: curl -s -H "Authorization: Bearer $RISKROUTER_API_KEY" \ https://api.riskrouter.eu/api/v1/ledger/export > ledger-export.json Then run two dependency-free Node scripts against it — standard library only, nothing to install, no call back to us. They live in a separate, public repository that shares no code with the service you are checking, on purpose: git clone https://github.com/aniljangrabe-dev/riskrouter-verify node riskrouter-verify/tools/verify-attestation.mjs ledger-export.json # we signed this head; we cannot deny it node riskrouter-verify/tools/verify-ledger.mjs ledger-export.json # your entries actually produce it Keep the export and the signed attestation somewhere we cannot reach. An export saved today still verifies against everything you hold, whether or not RiskRouter is still answering the phone a year from now. That is the actual answer to what happens if you disappear , not a promise standing in for one. Read the verifier before you trust it; it is short on purpose. If it is useful to you, star it on GitHub so the next compliance officer looking for one can find it. Want to see the chain break in real time instead of reading about it? Try it in your own browser — it lets you tamper with a record and watch the check refuse it. What we do not overclaim Precision matters more here than anywhere else on this site. Not "zero GDPR liability" A quote payload holds no personal data by design, which is a fact about the schema. It is not a legal conclusion about your own obligations, which depend on what you do with the response. Not "regulator-approved" Nobody has approved this. What exists is a record a regulator can independently verify without taking our word for it — a narrower, checkable claim. Not a validation build claiming live rails Every price on this site is a simulation while we validate; the ledger, the evidence log and their proofs are live. See exactly what is and is not in place on the regulatory position page . Go deeper Tamper detection, live Full regulatory position Data protection Ask us anything else ## Regulatory position URL: https://riskrouter.eu/compliance Regulatory position Where this platform sits under EU and Belgian insurance law, what it does with data, and which obligations belong to you rather than to us. Written so that a compliance officer can check it against the system rather than take it on trust. This is not an offer of insurance, and no cover is ever placed. Nothing this platform produces constitutes insurance mediation, distribution or advice within the meaning of Directive (EU) 2016/97. No policy is bound, no carrier is notified, no premium is collected and no payment instrument is touched at any point. What RiskRouter is Current status Frameworks IDD in the design Your obligations Limits of this page Position Infrastructure, not an intermediary RiskRouter supplies software: a pricing engine, a configurator and an audit ledger. It is not an insurer, not an insurance intermediary and not an ancillary insurance intermediary. It has no customers of its own, holds no client money, and carries no risk. Insurance distribution is performed by the licensed distributor who integrates it. That distributor owns the customer relationship, the product approval process and the regulatory permissions. We hold none of those and do not act as if we do. Where a licensed distributor uses this platform in production, we would be an ICT third-party service provider to a financial entity, with the contractual and oversight consequences that carries under DORA. That relationship is deliberately narrow and documented rather than implied. Status What is and is not in place Item Status Insurance distribution None. RiskRouter does not advise on, propose or conclude insurance contracts, and has no customers of its own Putting cover in force Not possible through RiskRouter: nothing on this site or in the API can bind a policy FSMA registration as an intermediary Not held, and not applied for. In our own analysis, software that does not distribute needs none. What the FSMA said, and what it did not Carrier or underwriting pool None, by design: the carrier relationship stays with the distributor Professional indemnity cover Not in place Client money None is held Pricing engine A simulated rate grid while we validate; its figures are not prices anyone can buy at Evidence log Live and append-only: signed heads, public timestamps and a Bitcoin anchor, checkable without us Quote ledger Live and append-only We publish no registration number, licence reference or carrier name, because we hold none. Every price the demo shows is a simulation produced by fixed server-side rules. Frameworks Which EU rules bite, and where Listing the ones that do not apply matters as much as listing the ones that do. A platform that claims coverage of everything has usually thought carefully about nothing. Framework Relevance Where RiskRouter stands Insurance Distribution Directive Directive (EU) 2016/97 Governs anyone distributing insurance, including the conduct, information and record obligations. Applies to the distributor, not to us. The platform is built so a distributor can meet the traceability and fair-presentation obligations rather than fight the tooling. Detail below. Belgian insurance law Act of 4 April 2014, supervised by the FSMA Transposes the IDD in Belgium and requires intermediaries to be registered before distributing. No registration held , and none is sought: RiskRouter does not distribute. The registered distributor who uses the platform does, under its own registration. GDPR Regulation (EU) 2016/679 Applies to any processing of personal data. A quote record contains no personal data at all. The personal data we do hold comes from the contact form and from email sent to our published address, and from nowhere else. Set out in full on the data protection page . DORA Regulation (EU) 2022/2554 Operational resilience for financial entities, and oversight of the ICT providers they depend on. Relevant the moment a regulated distributor depends on this platform. The audit ledger, the degraded-write behaviour and the ledger health probe exist partly for this. Formal contractual arrangements would be agreed per pilot. PRIIPs Regulation (EU) 1286/2014 Key information documents for packaged retail investment products. Not applicable. These are general insurance covers with no investment component. Solvency II Directive 2009/138/EC Capital and governance requirements for insurance undertakings. Not applicable. We underwrite nothing and carry no risk. It binds the carrier standing behind the cover. ePrivacy Directive 2002/58/EC Storage of, and access to, information on a user's device. No cookies and no third-party requests of any kind. The demo console keeps its engine address, and an API key only if you enter one, in your own browser. Arrivals from a tagged campaign link are counted by our own API with nothing stored on your device. Detail here and here . EU AI Act Regulation (EU) 2024/1689 Obligations attaching to AI systems, including risk assessment and pricing in insurance. Not applicable. Pricing is a fixed lookup table. There is no model, no inference and no automated decision-making about any individual. Design How the IDD shaped the build Traceability, Article 20 A distributor has to be able to show what was presented to a customer and on what basis. Every routing event is appended to a ledger that records the vertical, the exact true or false state of every component, the premium and the timestamp. The database refuses edits and deletions for every role including the administrative one, so the record cannot be tidied up afterwards. Which parts of Article 20 that evidences, and which stay with you, is set out duty by duty in IDD Article 20: what you need to be able to show . Fair, clear and not misleading, Article 17 Only the server prices a policy. It discards any price a browser sends and forces the mandatory base cover back on if a modified request tries to strip it. A customer therefore cannot be shown a number the engine would not charge. The same principle governs the audit trail. When a ledger write fails, the interface says no record exists rather than implying one does. A system that reports success it cannot evidence is precisely what an inspection is designed to find. Product oversight and governance, Article 25 The rating matrix is a single frozen object with one definition per component, published at a public endpoint so the interface renders exactly what the engine charges. A change to a price is a code change with a test that fails if the console or the documentation disagrees. That gives a product owner a reviewable, versioned record of every rate that has ever applied. What the platform does not do is decide whether a product is appropriate for a target market. That judgement belongs to the distributor and the manufacturer. Division of responsibility What stays with you Using this platform does not transfer any regulatory obligation to us, and no contract we could write would achieve that. A distributor integrating RiskRouter still holds: Registration with the FSMA, or the equivalent authority in your member state The demands and needs assessment, and the insurance product information document Product approval and target market definition under product oversight and governance Professional indemnity cover and the conduct requirements attaching to your permissions The customer relationship, complaints handling and any redress Controllership of your own customers' personal data We supply routing, deterministic pricing and an audit trail you can evidence. That is the whole of it, and we would rather say so plainly than let a diagram imply otherwise. Scope Limits of this page This describes a prototype we run for technical validation. It is not legal advice, carries no contractual terms, and claims no regulated activity. Statements about EU and Belgian law are given in good faith to explain design decisions, not as an authoritative reading. Take your own advice before distributing anything. If something here does not match what the system actually does, that is a defect and we want to know. Tell us and we will correct the page or the code. ## Data protection URL: https://riskrouter.eu/privacy Data protection Written to be checked rather than believed. Everything below can be verified against the schema and the network tab, and where something is a commitment rather than a mechanism, it says so. The short version Quote records Evidence log entries Contact enquiries Email correspondence Your browser Who else touches it Your rights Who is responsible Summary The short version Pricing a quote involves no personal data at all . There is no account, no login and no field for a name. We hold personal data in two places and no others : the contact form, and the mailbox behind our published address. Both are listed below with what is kept and for how long. No cookies, no trackers and no third-party requests. The site loads nothing from anyone else, which you can confirm in your browser's network tab. The only measurement is a daily count of arrivals from tagged links , which identifies nobody. Records are stored in Frankfurt, inside the EU . A daily backup of the ledger, encrypted before it leaves, is kept on GitHub for 90 days, outside the EU. It never includes the contact form. We sell nothing and share nothing for marketing. There is no advertising on this platform and never will be. Processing activity 1 Quote records A quote priced with a distributor’s API key is appended to an audit ledger, for the traceability a distributor needs under the Insurance Distribution Directive. A quote priced without a key is priced and not recorded. A record contains these fields, and none of them identify a person: Field Content id A random identifier generated by the database created_at When the quote was priced distributor_id Which distributor recorded it: a business, identified by the key it used active_vertical Which of the four risk verticals selected_components The true or false state of each cover component total_monthly_premium The premium the server computed matrix_version Which version of the rating matrix priced it compliance_status A fixed status string chain_index , prev_hash , row_hash Its place in the hash chain No IP address, no device or browser fingerprint, no session identifier and no cookie is recorded against a quote, and there is no field for the distributor’s customer. Two quotes for the same cover by the same distributor differ only in their time and their place in the chain. One use of your IP address, stated so it is not a surprise: to stop a single address flooding the engine, the API counts requests from each address over a one-minute window (60 quotes a minute) using Cloudflare’s rate limiting. That counter is kept by Cloudflare for the window and is never written to our database or joined to a quote. Because these records identify nobody, they fall outside the GDPR and are kept indefinitely as the audit trail they exist to be. The ledger refuses edits and deletions by design. Processing activity 1b Evidence log entries A distributor with a key can record the fingerprint of one of its own records, such as an advice note, in the evidence log. The record never reaches us: the distributor hashes it with a random salt it keeps, and sends only the resulting SHA-256 digest and a short tag such as idd.demands-needs . An entry holds its position in the log, when it was recorded, the distributor, the tag and the digest, and, if the distributor signs its entries, its key id, the time it claims and its signature. To us, a digest identifies nobody: we never hold the record or its salt, and a salted digest cannot be reversed. The distributor holds both, so for the distributor the digest belongs with its record and its own obligations for that record. The record stays in the distributor’s systems, where it can be erased; erase the record and its salt, and the digest left in the log cannot be linked to anyone, by anyone. Entries are kept permanently, on the same append-only terms as the quote ledger. How a digest is made Processing activity 2 Contact enquiries If you use the contact form, we store what you typed so we can reply. Nothing more is inferred, appended or enriched. Question Answer What we store Your name, email address, organisation if you give one, the enquiry type and your message What we do not store Your IP address, any tracking identifier, or anything you did not type — with one exception: if you reached the form through a link carrying a campaign tag (such as ?src=linkedin-sept ), that tag is stored with your message so we know which conversation brought you Why we may hold it Legitimate interests under Article 6(1)(f): you asked us a business question and we need to answer it How long Twelve months from your last contact, then deleted Who sees it The project owner. It is not shared, sold or passed to any third party Automated decisions None. Nothing about you is scored, profiled or decided by a machine The twelve-month limit is enforced by a scheduled job in the database, not by someone remembering to run a query. A retention policy nobody implements is a statement, not a safeguard. Processing activity 3 Email correspondence We publish anil@riskrouter.eu , so anything you send there is personal data we hold. Saying the form was the only such place would have been convenient and wrong. Question Answer What we store Your message and whatever your mail client puts in it: your address, your name as you send it, and the technical headers of the message Where it sits A Microsoft 365 mailbox. Microsoft is the processor for that mailbox, under its own data protection terms Why we may hold it Legitimate interests under Article 6(1)(f), the same basis as the form: you wrote to us and we need to answer How long Twelve months from our last exchange, then deleted Who sees it The project owner. It is not shared, sold or passed to any third party One honest difference from the form: that twelve-month limit is a rule a person applies, not a scheduled job in a database. If the difference matters to you, use the form — it is enforced there, and we would rather you knew which of the two we can prove. Your device What we keep in your browser No cookies are set by this site, for any purpose, including analytics. There is nothing to consent to because nothing is tracked. The demo console saves up to two values in your browser's local storage, so you do not have to retype them: the address of the pricing engine it should call, and, only if you enter one, your API key. The address never leaves your device. The key is sent only with requests to our own engine (or to one running on your own machine), never to any other address you type in. We cannot read either from your browser; emptying the key field removes the key, and clearing your site data removes both. The try it panel on the API reference keeps a key in the open tab’s memory only. Nothing else is stored client-side. Campaign counts When we share a link we sometimes tag it with a campaign name, such as riskrouter.eu/integrate?src=linkedin-sept . If you arrive on such a link from another site, the page tells our own API the campaign name and the page, and we add one to that day’s count. That is all that is sent: no IP address is stored, no identifier, no browser details, and nothing is written to your device — the tag travels in the links on the page, not in a cookie or in storage. The result is a table of numbers per day, campaign and page, which cannot be tied to any person and is not personal data. The same tag is kept with a sandbox key you take, and with a message you send, so we can tell which campaign produced a trial or a conversation. Arrive without a tag and nothing is counted at all. Sub-processors Who else touches the data Provider Role Where Cloudflare Serves the pages and runs the pricing engine Processed at the network location nearest to you, which may be outside the EEA. Nothing is stored there. Supabase Hosts the database holding quote records and contact enquiries Frankfurt, Germany GitHub Keeps the daily backup of the ledger and the distributor records, for 90 days. It never includes contact-form enquiries. The backup is encrypted (AES-256) before it is uploaded, with a passphrase GitHub does not hold, so GitHub stores it but cannot read it Outside the EU Microsoft Runs the mailbox behind our published address, so anything you email us passes through it Microsoft 365, under Microsoft’s own data protection terms That is the complete list. There is no analytics provider, no email marketing platform, no customer data platform and no advertising network, because the site makes no requests to any of them. Open your network tab and count. Microsoft appears only because we publish an email address; it touches nothing the platform itself stores. Request routing through Cloudflare means the processing of a request in transit can happen outside the EEA even though the stored record does not. We would rather state that plainly than claim an EU-only guarantee the architecture does not support. Your rights What you can ask for Where we hold personal data about you, which means the contact form and our mailbox and nothing else, you can ask us to give you a copy, correct it, delete it, restrict what we do with it, or object to us holding it at all. Ask through the contact form or at anil@riskrouter.eu , and we will act within one month. Because our basis is legitimate interests rather than consent, you can object at any time and we will stop unless we have a compelling reason not to. In practice, for a business enquiry, there will not be one. If you are unhappy with how we handle it, you can complain to the Belgian Data Protection Authority, the Gegevensbeschermingsautoriteit or Autorité de protection des données, or to the supervisory authority in your own member state. Accountability Who is responsible RiskRouter is a validation prototype operated by its project owner rather than by an established company. No legal entity, registered address or data protection officer is published here, because publishing one that does not exist would be worse than publishing none. Both will appear before any production processing begins, and this page will be updated when they do. Where a licensed distributor deploys this platform for their own customers, that distributor is the controller for their customers' data and we would be a processor acting on their instructions under a written agreement. Nothing on this page changes that division. For anything concerning your data, including the rights set out above, write to anil@riskrouter.eu or use the contact form . Both reach the same person, which is the whole of the organisation today. If anything here does not match what the system does, treat it as a defect. Tell us and we will fix the page or the code, whichever is wrong. ## Contact RiskRouter URL: https://riskrouter.eu/contact Contact Write to us about a pilot, an integration question, or something on the regulatory pages you think is wrong. A person reads every message. There is no sales sequence and no newsletter. Send a message Your name Email Used to reply to you. Nothing else, ever. Organisation (optional) What is this about Running a pilot Integration or technical question Regulatory or data protection Something else Message At least ten characters. Leave this field empty Send message We store your name, email, organisation and message so we can reply, on the basis of legitimate interests, and delete them twelve months later. That deletion runs on a schedule in the database rather than depending on anyone remembering. How we handle it . What to expect Straight answers If you are evaluating this for a checkout, say what you sell and roughly what volume. That is usually enough for us to tell you whether it fits, including when it does not. If you found something wrong on the compliance or data protection pages, quote the line. Those pages are meant to be checkable, and a correction is worth more to us than a compliment. Before you write Two things worth knowing We are not selling insurance. RiskRouter is infrastructure for licensed distributors. If you were looking to buy cover for yourself, we cannot help and would rather say so now than take your time. RiskRouter holds no FSMA registration and does not distribute insurance, so a pilot means building and testing with your product, under your own registration. The regulatory position spells out where the line sits. The other channel Or write directly anil@riskrouter.eu The form is still the better route, and not for our convenience: it writes straight to a database in Frankfurt under a twelve-month deletion schedule you can read in full. An email sits in a mailbox instead, so it is governed by a rule someone has to apply rather than one the database enforces. Both are covered on the data protection page ; only one of them is automatic. No legal entity is registered yet, so none is named here. When one exists its details will appear on the data protection page . ## Verify the ledger URL: https://riskrouter.eu/verify Verify the ledger yourself Every platform in this market says its audit trail can be trusted. Ours can be checked. Record the hash below today, and you can prove later that not one historic quote was altered, without asking us for anything and without taking our word for it. Live Current head of the chain Read straight from the running ledger. It changes with every quote priced. … Entries chained SHA-256 Digest … As of (UTC) Head hash loading… Copy head hash Keep it with today's date. That single string commits to every entry written so far. How it works Each entry seals the one before it When a quote is priced, the database computes a SHA-256 digest over that entry's contents and the previous entry's digest , before the row is written. Change any field of any historic entry and its digest no longer matches, and neither does every digest after it. The break is visible at the exact entry. The canonical form is deliberately plain, so any language can rebuild it: sha256( chain_index | id | created_at | vertical | components(key=true|false, sorted by key, comma separated) | premium(0.00) | status | matrix_version | distributor_id | prev_hash ) No JSON formatting, no key-order dependence, no locale. The first version of this used PostgreSQL's own JSON output and was replaced, because a chain only one database can rebuild is a claim rather than evidence. distributor_id is inside the digest, not beside it. Attribution that sat outside the hash could be reassigned after the fact with every digest still verifying — which would make the chain evidence of what was quoted but not of who quoted it. Do it yourself Four commands, none of which need us The verifier shares no code with the database. It rebuilds every digest in Node. # 1. today: save the whole signed attestation, not just the hash curl -s https://api.riskrouter.eu/api/v1/ledger/attestation > 2026-09-20.json node tools/verify-attestation.mjs 2026-09-20.json # 2. any time: export your own entries and the chain they sit inside curl -s -H "Authorization: Bearer $RISKROUTER_API_KEY" \ https://api.riskrouter.eu/api/v1/ledger/export > export-2026-09-20.json # 3. check it. the first proves we signed this head, the second proves # your entries are what produces it node tools/verify-attestation.mjs export-2026-09-20.json node tools/verify-ledger.mjs export-2026-09-20.json # 4. months later: a head you recorded must still come out of history node tools/verify-ledger.mjs export-2027-03-01.json --expect-head # 5. to show one quote to a regulator or a customer, and no other node tools/entry-proof.mjs export-2026-09-20.json 42 > entry-42.json node tools/verify-ledger.mjs entry-42.json A mismatch at step 4 means history changed. There is no version of that sentence where we get to explain it away. Step 5 cuts a single-entry proof : that entry in full, its links to the head, and the signed attestation. It proves the entry’s content produces the digest the ledger published for its position. The links after it are followed by digest only, as in any export; they bind because anyone who later recomputes the full ledger must reach the signed head, and cannot if that entry was changed or removed. You can also make one on this page, below, after checking an export. Step 2 used to read differently. It told you to pull the rows out of the database with a Supabase key — a credential you will never hold, because ours never leaves the Worker. So the independent check this page promised was one no customer could actually run. A proof that needs the operator’s cooperation is not a proof, it is a courtesy, and we would rather say that plainly than leave the old instruction sitting there looking reassuring. Save the whole response rather than copying the hash out of it. The signature is what turns a string you typed into a commitment we made: it covers the head hash, the entry count and the time together, so none of the three can be changed afterwards without the signature failing. The public key is in anchors/signing-key.json in the repository. Checking against a key we hand you at the moment you check would prove nothing, if we are the thing in question. Check a file here Drop in your export. It is checked in this browser, not by us. The same checks as the commands above, run on this page: the signature on the head, every link in the chain, and each of your own entries rebuilt from its content. The file is read by your browser and never sent anywhere — this section makes no network request at all, and a test in the repository fails if one is ever added. Choose a file or drop it here An export from /api/v1/ledger/export , a single-entry proof, a saved attestation, or the rows downloaded from the demo below. Head you recorded earlier (optional) Show one quote without showing the rest. Pick one of your entries and download a single-entry proof: that entry in full, its links to the head, and the signed attestation. Whoever you give it to can check it here or with the public verifier, and learns nothing about your other quotes. Download proof Which public key is this checked against? The one published in anchors/signing-key.json and in the public verifier repository , key id . Be clear about what that means: this page is served by us, so the key it carries is also one we handed you just now. If you saved a copy of the key earlier, load it here and the check uses yours instead. Use my own copy of the key using the key embedded in this page The same reasoning applies to the code: a page we serve could, in principle, be made to say INTACT regardless. That is why this is a convenience and the commands above are the proof — they run code you hold, against a key you hold, and share nothing with this site. Break it yourself Change a premium and watch the chain refuse it Four entries, chained exactly as the real ledger chains them — same canonical form, same SHA-256, computed in your browser. Edit any premium below. The entry you touch stops matching its own digest, every entry after it stops linking, and the head moves. Nothing here talks to us, and nothing you type leaves the page. # Vertical Premium /mo Digest Status Head after your edits: Download these rows Reset the chain The download is the part worth doing. Drop it into the checker above , or run the independent verifier over it, and both reach the same conclusion this page did — including the entry number where it broke: node tools/verify-ledger.mjs rows.json Two implementations that share no code agreeing on where history was altered is the whole argument. A test in this repository asserts that the function running in your browser and the one in tools/verify-ledger.mjs produce byte-identical canonical strings, so the demonstration cannot quietly drift away from the thing it demonstrates. Continuity What you keep if RiskRouter stops existing RiskRouter is run by one person. You should ask what happens to your audit trail the day it stops, and the answer should not depend on our goodwill on that day. An export you have already downloaded keeps working after we are gone. It contains: Every one of your entries in full, so each digest can be rebuilt from its own content. The (chain_index, row_hash, prev_hash) of every entry in the ledger — opaque digests, no one else’s content — which is what links your entries to the head. The signed attestation for that head, and the id of the key that signed it. The verifier is forty lines of standard-library Node in a public repository, the public key stays in anchors/ including after any rotation, and neither needs a server to run. Download an export once a month and you hold evidence that outlives the company that issued it. That is the opposite of lock-in, and it is deliberate: a product whose value depends on you being unable to leave is a product we would not want to sell. The full continuity and exit plan covers what stops, how to leave, and the facts your DORA register needs. What a copy cannot reproduce How old the record is 13 September 2026 first head anchored 1 head anchored 967 830 earliest Bitcoin block 46 entries that head covers none yet independent witnesses 2 heads with RFC 3161 time Everything else on this site could be rebuilt by someone else. These figures could not. They are computed, each time the site is built, from the signed anchors and timestamp proofs in anchors/ and the public keys in witnesses/ , and from nothing else; the same figures are published as proof-of-age.json . The 13 September 2026 head is in Bitcoin block 967 830: whatever anyone says later, including us, it existed before that block was mined. 2 heads carry an RFC 3161 time-stamp token from DigiCert timestamp service and Sectigo timestamp service, the latest issued at 2026-09-28 09:46:47 UTC. None is a qualified eIDAS time stamp: they are evidence of time from an independent authority, without the legal presumption a qualified one carries. No independent party co-signs the evidence log yet, and the page says so rather than leaving the figure out. How to become a witness . Honest limits What this does and does not prove Claim Status A historic entry was altered or deleted Detectable by anyone holding an earlier head Entries were re-ordered or a gap introduced Detectable An entry was fabricated and inserted into the past Detectable A quote was never written at all Not detectable. A chain proves what is there, not what is missing The premium was correct when it was quoted Separate control: the rating matrix is versioned and stamped on every entry Someone rebuilt the whole chain from scratch Detectable against any head recorded beforehand. node tools/verify-anchors.mjs export.json checks a ledger against every head published in anchors/ , and a rebuild cannot reproduce one taken before it. Residual limit: that directory is ours, so a rebuild plus a force-push could remove the anchor too — not from a copy you already hold, which is the reason to keep one We deny ever having published the head hash you hold Every attestation is signed. One you saved is ours whether we like it or not A head hash was published before the entries it covers existed Bounded, for anchored heads. The 13 September 2026 anchor was submitted to three independent OpenTimestamps calendars on 20 September, and those proofs are now upgraded to Bitcoin attestations for blocks 967830, 967831 and 967860. So that head, and the 46 entries it covers, existed no later than block 967830 was mined. It proves an upper bound, not the exact moment: the time between an entry and the next anchored head is still our word. Check a proof yourself with ots verify , which compares it with the block’s header; the files are in anchors/ The last row is the honest one, and it is the reason the row above it matters. Publishing the head is the commitment; a signature means we cannot later say we never made it; keeping your own copy is what makes it binding. What none of that establishes on its own is when . Bitcoin does that for anchored heads: a head timestamped there existed before that block was mined, whatever we say later. Heads are anchored weekly when the ledger moves, so the window in which a time is only our word is at most about a week plus the time a block takes to confirm. ## IDD Article 20: what you need to be able to show URL: https://riskrouter.eu/guide-idd-article-20 Guide for insurance distributors IDD Article 20: what you need to be able to show Article 20 of the Insurance Distribution Directive, Directive (EU) 2016/97, is about the sale itself: what the customer needs, and whether what you proposed fits. It never uses the word record . But every duty in it is one you may be asked to demonstrate long after the conversation is over, and the only way to demonstrate it is with evidence you kept at the time. The text What Article 20 asks of a distributor Before an insurance contract is concluded, the distributor must: Specify the customer’s demands and needs , on the basis of information obtained from the customer. Give objective information about the product in a comprehensible form, so the customer can make an informed decision. Propose only what fits. In the directive’s words: Any contract proposed shall be consistent with the customer’s insurance demands and needs. Where advice is given, explain it : a personalised recommendation explaining why a particular product would best meet the customer’s demands and needs. For non-life products, hand over the standardised insurance product information document (the IPID). Article 23 then governs how that information reaches the customer: on paper, or on another durable medium or a website where the conditions for that are met. In Belgium the directive is transposed by the Act of 4 April 2014 on insurance, and the FSMA supervises its conduct rules. Evidence Each duty, and what would show you met it A duty you cannot evidence afterwards is, in an inspection or a complaint, a duty you cannot show you met. This is the practical reading: for each part of Article 20, the question someone will eventually ask, and what answers it. The last column says honestly which parts a system like RiskRouter can evidence and which stay entirely with you. Duty The question you will be asked Who holds the evidence Demands and needs What did the customer tell you, and what did you conclude they needed? You. RiskRouter records no customer information at all, by design. Consistency of what was proposed Exactly what was proposed: which product, which options, at what price, when? RiskRouter records this: the vertical, the on or off state of every component, the premium, the rating-matrix version and the time, in an entry nobody can edit afterwards. Objective information Was the price you showed the price the rules produced, and which rules were they? Partly. The server computes every price and ignores any a browser sends, and each entry carries the version of the rate table that priced it. The wording you showed stays in your own system. Personalised recommendation Where you advised, what did you recommend and why? You. IPID (non-life) Which version of the product information document did the customer receive? You, and your product manufacturer. Durable medium (Article 23) How and when did the information reach the customer? You. How long to keep this evidence is not something this page states. Check the period that applies to you with your supervisor or your professional federation. The weak point Evidence that could have been edited proves less Most distributors do keep records: a CRM note, a spreadsheet, a PDF in a shared drive. The difficulty is that every one of those can be changed after the fact by anyone with access, and usually leaves no trace when it is. A record that could have been corrected is a record whose accuracy rests on your word, which is exactly what it was meant to replace. That is the gap an append-only, hash-chained ledger closes: changing any entry breaks every entry after it, and anyone holding an earlier checkpoint can see that it happened. The difference is set out in database log vs tamper-evident ledger , and you can watch a chain refuse an edit on the verify page . Scope What this page is not This is a plain-language reading of the directive, written to explain why RiskRouter records what it records. It is not legal advice and not an authoritative interpretation; your own counsel, your supervisor and your federation are. Using RiskRouter transfers none of your obligations to us. The regulatory position sets out what stays with you in full. Get a sandbox key The audit-trail checklist ## Audit-trail checklist for insurance brokers URL: https://riskrouter.eu/guide-audit-trail-checklist Guide for brokers and distributors Audit-trail checklist for insurance brokers Twelve questions to put to any system that holds the record of what you quoted: your CRM, your broker software, a spreadsheet, or us. They are written for a broker in Belgium, where the FSMA supervises the conduct rules of the Insurance Distribution Directive, but nothing in them is Belgian-specific. Our own answer follows each one, including where it is no. 1 3 What is in the record Does it hold what you would be asked for? Question Why it matters RiskRouter 1. Does each entry say exactly what was proposed? Travel cover, about 6 does not show the proposal fitted the customer’s needs. Every option, on or off, does. Yes. The vertical, every component’s on or off state, and the premium in integer cents. 2. Does it record which price rules applied? A price changes. Without the version, a two-year-old quote cannot be explained. Yes. Every entry carries the rating-matrix version that priced it. 3. Does it record the demands and needs assessment? It is the heart of IDD Article 20. See what Article 20 asks . No. We hold no customer information, so that assessment stays in your own system. 4 7 Integrity Could the record have been changed? Question Why it matters RiskRouter 4. Can anyone edit or delete an entry, including an administrator? If an administrator can, the record is only as good as that administrator’s word. No one can. The database refuses edits and deletions for every role, including the administrative one. 5. If an entry were changed, would anyone be able to tell? Preventing edits is a policy. Detecting them is evidence. Yes. Entries are hash-chained: changing one breaks every entry after it. Try it. 6. Can the vendor deny a checkpoint it gave you? A checkpoint the vendor can disown protects the vendor, not you. No. Every attestation of the chain’s head is signed; one you saved is ours whether we like it or not. 7. Is the time of each entry independently proven? Without it, when is still the vendor’s word. Bounded. Our 13 September 2026 head is timestamped in Bitcoin (blocks 967830 and later, via three OpenTimestamps calendars), so every entry it covers existed before that block. The exact time between an entry and the next anchored head is still our word; heads are anchored weekly. 8 10 Independence Can you check it without the vendor? Question Why it matters RiskRouter 8. Can you export your own entries at any time? Evidence you can only see inside the vendor’s screen is evidence the vendor controls. Yes, one authenticated request, no one to ask. 9. Can you verify the export without the vendor’s software? If the checker is theirs, the check is theirs. Yes. Dependency-free verifiers in a separate public repository , or the checker on the verify page , which runs in your browser and sends nothing. 10. Does the evidence survive the vendor going out of business? The record has to outlive the contract. Yes. An export you already hold verifies with no connection to us. 11 12 Honesty and data protection Does it tell the truth when it fails, and keep personal data out? Question Why it matters RiskRouter 11. When a write fails, does the system say so? A system that shows saved for a record that does not exist is the failure an inspection is designed to find. Yes. A quote whose entry was not written is reported as not recorded, never as a success. 12. Is personal data kept out of the permanent record? A record nobody can edit is also a record nobody can erase. Under the GDPR, personal data in it would be a problem you cannot fix later. Yes. A quote entry has no field for a name, an email or an identifier. See data protection . One thing no system of this kind can prove: that every quote you gave was sent to it. A quote that was never recorded leaves no trace to find. A chain proves what is in it, not what is missing, and anyone who tells you otherwise is describing something else. Scope How to use this list Use it on any supplier, including us, and ask for the evidence behind each answer rather than the answer. It is a practical checklist, not legal advice, and it does not say how long you must keep records: check that with your supervisor or your professional federation. Check our answers with a sandbox key Log vs ledger, explained ## Database log vs tamper-evident ledger URL: https://riskrouter.eu/guide-database-log-vs-ledger Guide for compliance, audit and engineering Database log vs tamper-evident ledger Almost every system that sells insurance keeps an audit log. Almost none of those logs could show that they have not been edited. That is not a flaw in any particular product; it is what a database table is. This page explains the difference in plain terms, using our own ledger as the worked example, and says what a ledger still cannot prove. The ordinary case What an audit log in a database is A table with one row per event: who, what, when. It is genuinely useful, and it answers most day-to-day questions. Its limit is that every row is just data. Whoever can write to the database, whether an administrator, a support engineer, a migration script or someone restoring a backup, can change a row, delete one or insert one in the past, and the table afterwards looks exactly as if it had always been that way. Logging the changes to the log does not help, because that second log is also a table. The record is as trustworthy as the least careful person with access to it, which is why a regulator or a court may treat it as your account of events rather than as evidence of them. What changes What makes a ledger tamper-evident 1. Each entry is sealed to the one before it Every entry is reduced to a fixed text form and hashed with SHA-256, and that hash includes the previous entry’s hash. Change one premium in one old entry and its hash changes, so the next entry no longer links to it, and nor does anything after. The newest hash, the head , therefore stands for the entire history. 2. The database refuses to rewrite it In our ledger, updates and deletions are refused by the database itself, for every role including the administrative one. That is prevention. The chain is what makes it more than a policy: if the refusal were ever bypassed, the chain would show it. 3. The head leaves the building A chain only proves something against a head someone else already holds. Ours is published in a signed attestation that anyone can fetch and keep, and past heads are committed to the public verifier repository . Once you hold one, any later rewrite of the history before it is detectable by you, without asking us. 4. The head is signed A signature means a head you saved cannot later be disowned as something we never published. You can check one in your browser on the verify page , or with the scripts in the public verifier . Side by side The same questions, asked of each Question Audit table Tamper-evident ledger Can an administrator change an old entry? Yes, silently Refused by the database, and detectable if forced Could an entry be inserted into the past? Yes, silently Detectable Could entries be reordered or one removed? Yes, silently Detectable Could the whole history be rebuilt from scratch? Yes Detectable against any head recorded beforehand Can someone outside check it? Only by trusting a screen or a copy Yes, from an export, offline Does it prove a quote that was never written? No No. A chain proves what is there, not what is missing Does it prove when each entry was made? No An upper bound, once a head is timestamped. Our 13 September 2026 head is in Bitcoin block 967830 and later, so its entries existed before that block. The exact moment is still our word Trade-offs What it costs you Nothing in a ledger can be corrected, only followed by a new entry. That is the point, and it has a consequence: personal data must never go into it, because under the GDPR a person can ask for their data to be erased and an entry that cannot be changed cannot be erased either. Our quote entries have no field for a name, an email or an identifier for exactly that reason; the personal data you hold about a customer stays in your own system, where it can be deleted. Scope What this page is not A technical explanation, not legal advice. Whether a given record meets a given obligation is for you, your counsel and your supervisor to judge. What we can offer is a record whose integrity you can check yourself, which is a better starting point for that judgement than one you have to take on trust. Watch a chain refuse an edit Get a sandbox key ## Security and vulnerability disclosure URL: https://riskrouter.eu/security For security reviewers and researchers Security and vulnerability disclosure If you have found a way to break something here, we want to hear it, and we would rather hear it from you than read about it. This page says where to write, what is in scope, what we promise in return, and which controls are already in place, so you can check them rather than take them on trust. Report How to report Email anil@riskrouter.eu with security in the subject. Say what you found, how to reproduce it, and what you think the impact is. English or French. The same contact is published at /.well-known/security.txt . RiskRouter is run by one person, so you will be writing to the person who wrote the code. We aim to acknowledge a report within five working days and to tell you what we are doing about it. We will credit you when it is fixed, if you want to be credited. There is no bug bounty: we have no money to offer, and would rather say so than imply otherwise. Scope What is in scope riskrouter.eu : the site and the demo console. api.riskrouter.eu : pricing, recording, the ledger export and attestation, the evidence log and its proofs, checkpoints, the MCP endpoint, sandbox keys. The ledger’s guarantees : any way to change, insert, reorder or delete an entry without it being detectable, to get an attestation signed that we did not produce, or to make a failed write look like a success. Attribution : any way to record against a distributor without that distributor’s key, or to read another distributor’s entries. The public verifier at github.com/aniljangrabe-dev/riskrouter-verify : any input that makes it report a tampered ledger as intact. Please do not Test for denial of service or send floods of requests. The ledger’s ceilings are deliberate and documented. Try social engineering, or anything involving our email provider or hosting providers’ own systems. Record personal data in the ledger. Entries can never be deleted, so anything you put there stays forever. A sandbox key is enough to test recording. Access, keep or share data that is not yours beyond what you need to show the problem. Research that follows this page, in good faith, is welcome. We will not pursue legal action against it. Controls What is already in place, and how to check it Control What it does Check it Content-Security-Policy Every page may run only the scripts it shipped with, listed by hash. No third-party script, no inline code that was not there at build time, no framing. Response headers of any page No third-party requests The site loads nothing from any other origin: no CDN, no font service, no analytics. Your browser’s network tab Transport and framing HSTS, nosniff , framing denied, a strict referrer policy, on the site and the API. Response headers Keys stored as digests Only the SHA-256 of an API key is ever stored. A copy of our database would contain no usable key. API reference Append-only ledger The database refuses edits and deletions for every role; entries are hash-chained and the head is signed. Verify page One outbound destination The API Worker contacts nothing but its own database. An automated test fails the build if a new destination appears. Trust page Admin behind an identity check The admin console sits behind Cloudflare Access and verifies each session’s signature. It can do five things, none of which touch a quote or the ledger. Not publicly reachable, by design Honestly What we have not done No external penetration test and no security certification. We claim neither. The controls above are what a one-person validation build can put in place and let you check; if a regulated distributor needs an independent assessment before a pilot, that is a reasonable thing to ask for and to plan together. Sending us your vendor questionnaire? Most of it is already answered, with evidence, on the security questionnaire page. ## Continuity and exit plan URL: https://riskrouter.eu/continuity For procurement, risk and DORA review Continuity and exit plan RiskRouter is run by one person and has no legal entity registered yet. If you depend on it, you should know what happens the day it stops, and the answer should not rest on our goodwill that day. DORA asks a financial entity to have an exit strategy for each ICT provider it relies on; this page is the part of that strategy we can write for you, and it says where it falls short. What you keep Your evidence outlives us Your entries, whenever you want them. One authenticated request to GET /api/v1/ledger/export returns every entry you recorded, the digest skeleton of the whole chain they sit in, and the signed head. No ticket, no notice, no fee. A verifier we do not control the outcome of. Dependency-free verifiers in a public repository that shares no code with the service. Clone it now and it keeps working without us. The public key and past heads. Published in that same repository, so an export you hold can be checked against a key and a head you did not get from us on the day. An open format. The export is JSON, and the canonical form of an entry is documented on the verify page , so any engineer can re-implement the check. What makes this real is the copy you take. An export saved regularly, kept somewhere we cannot reach, is evidence that survives RiskRouter. One you meant to download is not. What stops What stops if we stop Function If RiskRouter stops What you need in place Pricing The API stops answering. A fallback for quoting, or your own copy of the engine (see below). Recording new quotes Stops. A quote after that point is not in our ledger. Your own record of new quotes from that date. Your existing evidence Unaffected, if you hold an export. Regular exports, stored by you. Checking that evidence Unaffected. A clone of the public verifier. Backups Restore tested, and what backups exist A restore drill runs every day, and every run so far has passed. Each day a backup of the production ledger and the evidence log is taken and restored into a fresh database, automatically; a failed drill alerts the owner and is written up on the changelog . The first drill was run by hand on 23 September 2026, and the job has run on a schedule since. In the first drills, all 46 entries came back, the database’s own chain check and an independent rebuild both reached the same head, that head is the one signed on 13 September and timestamped in Bitcoin, and the restored ledger still refused every edit and deletion. Loading took under a second; a real recovery would take as long as noticing, deciding and repointing the service. What is not in place yet: the database runs on a plan that keeps no backups of its own. The only backups are our daily ones, kept encrypted on GitHub for 90 days, so entries recorded since the last one, at most a day’s, would be lost with the database. Your own exports are not affected: they verify without us. Exit The steps to leave, in order Take a final export and verify it with the public verifier, offline. Save the signed attestation it contains, and a copy of the public key from the verifier repository. Stop sending your key; record new quotes in your own system from that date. Ask us to revoke your key, so nothing more can be recorded in your name. Keep the export for as long as your own retention obligations require. None of these steps needs our cooperation except the revocation, and even without it an unused key records nothing. That is deliberate: an exit that depends on the provider is not an exit. Running it yourself It runs in your own account, and the source is not public today The engine is small: a SQL schema and one Worker, with no proprietary runtime. There is a deployment kit for running that same code in your own account: on your own Cloudflare and Supabase, or anywhere containers run (PostgreSQL, PostgREST and the API, started with one command). Your instance signs its heads with its own key, holds its own data, and calls nothing of ours: no licence server, no telemetry. Anchoring, witnesses and the conformance suite work against your instance the same way they work against ours. The kit is built and exercised end to end from nothing every week in our CI: a distributor and a key, a quote recorded, evidence recorded, and every signature checked with the instance’s own key by both verifiers. The engine’s source code is still in a private repository; what is published is the verifier, the drop-in recorders (Apache-2.0), and the integration and conformance kits. So running it yourself needs the source and a licence from us, agreed in writing. If that is a condition of your pilot, say so before it starts, and agree how you would get the source if we stopped: direct access, or an escrow arrangement. We would rather settle that at the start than have you discover it at the end. DORA Facts for your register of information A financial entity keeps a register of its contractual arrangements with ICT third-party service providers. These are the facts about us you will need for it. The ones that count against us are stated as plainly as the rest; whether the function we support is critical or important is your assessment, not ours. Item RiskRouter Provider RiskRouter. No legal entity is registered yet, so there is no LEI and no company number. A contract can only be signed once one exists. Service Software delivered as an API: deterministic server-side pricing from a published rating matrix, and an append-only, hash-chained audit ledger with a signed head. Function it supports Pricing configurations, and recording what was quoted as evidence for your IDD obligations. It does not hold the customer relationship, the demands-and-needs assessment, the IPID, claims or payments. Personal data None in a quote entry, by design. Enquiries sent through our contact form are the only personal data we hold, and they are not part of the service. Where data is stored Supabase, Frankfurt, Germany (EU). An encrypted daily backup is kept on GitHub for 90 days, outside the EU. Where it is processed Requests are handled by Cloudflare at the network location nearest the caller, which may be outside the EEA. Nothing is stored there. Subcontractors Cloudflare (network and compute), Supabase (database), GitHub (encrypted backups), Microsoft (the mailbox behind our published address). Listed on the data protection page . Substitutability Your data leaves in full, in an open format, verifiable without us. Pricing and recording would need replacing: see what stops, above. Exit plan This page. Certifications and audits None. No penetration test and no certification is claimed. See security . Service level, incident notice None offered today. To be agreed in writing per pilot. Contract terms Each provision DORA Article 30 requires, and the clause we offer for it: DORA Article 30, clause by clause . Status Validation build. Mock pricing, no carrier, no cover in force. See the regulatory position . Try the export with a sandbox key Discuss a pilot’s terms ## Changelog and rating matrix history URL: https://riskrouter.eu/changelog For product owners and integrators Changelog and rating matrix history What changed, and when. The rating matrix comes first, because a quote recorded today may need explaining in two years, and the explanation starts with which prices applied. Everything below the matrix is taken from the repository’s own history. Rating matrix Every version of the prices Every recorded entry carries the matrix_version that priced it, and that field is inside the entry’s hash, so it cannot be changed afterwards. The fingerprint is the SHA-256 of every price, one line per component ( vertical|code|cents ), sorted; recompute it from GET /api/v1/verticals or with node tools/matrix-fingerprint.mjs . A test fails if a price changes without a new version and a new row here. Version In force What changed Fingerprint 2026.09.1 12 September 2026 to date First published matrix: four verticals, each a mandatory base layer and four optional modules, 20 prices. Mock rates for validation, not offered to anyone. 06918cd51b6df7c637a972af673957f05a9f7f246aaed5a6f5c49e270aadd600 The first 43 entries in the ledger, recorded on 12 September 2026 before the version field existed, carry no version. They were priced by the same rates: no price has changed since the engine was first deployed that day. Changes What changed, most recent first 30 September 2026 AI agents can connect to the evidence log over the Model Context Protocol at https://api.riskrouter.eu/mcp : read the signed head, proofs, the checkpoint and usage without a key, and record a digest with one. Each tool is an existing route, answered by the same code. There is no pricing tool. How to connect Opening https://api.riskrouter.eu/mcp in a browser now shows a page saying what the address is and how to connect, with its tools; MCP clients get exactly what they did before. And the endpoint is ready to be listed in the official MCP Registry as eu.riskrouter/evidence-log . AI agents and assistants : one page to connect Claude Code, Cursor or any MCP client to the evidence log, with the tools and which need a key, the agent framework adapters and AI Act logging. And /llms-full.txt : every English page as text, for AI assistants, rebuilt with the site. Sealed security logs : logseal , in the recorder kit, seals any log stream segment by segment, so after a breach you can show which logs existed before it and that none was rewritten or removed, while the logs stay on your own storage. A sixth pack, NIS2 and data breaches, records each segment, each incident stage and each report sent, mapped to NIS2 Articles 21 and 23 and GDPR Articles 33 and 34. It detects nothing and names no attacker; it keeps the evidence trustworthy. Load tested on every change to the engine, against the self-hosted stack: the log ceiling (600 entries a minute) and the per-caller limit (60 requests a minute) both held exactly and answered a clean 429, batches of 50 were recorded in about 22 ms, no request failed with a server error, and every accepted entry was in the tree. These are test-machine figures, not production ones. In French, Dutch and German: the home page and what the law asks you to record ( NL , DE ), with each article linked to the EUR-Lex text in that language and a language switch on every page that has a translation. The API, the specification and most pages remain in English, and the translated pages say so. The drop-in recorders are now tested through an outage: the log refusing everything, then writing a batch whose answer is lost, then back, with the process killed in between. Nothing is lost and nothing is marked recorded before the log answered; a lost answer costs a duplicate leaf, never a gap. Recorders Uptime, measured from outside: GitHub Actions, which runs on none of our infrastructure, probes the website and the API about twice an hour and keeps every answer, and /status shows the last 30 days. Time GitHub did not probe is shown as not measured, never as up; a degraded API is counted apart. The figures as JSON: /uptime.json . Backups are now daily and kept for 90 days, each restored into a fresh database and checked the same day; they were weekly, kept 30 days. At most a day of entries now separates the database from its last backup. Restore drill DORA Article 30, clause by clause : every provision a contract with an ICT provider must contain, the clause we offer for it, and what is in place today, including what is not. Proposed terms until RiskRouter’s legal entity exists. What the law asks you to record : for IDD, MiFID II, the AI Act, GDPR Article 22 and DORA, what each article asks, when the record gets tested, and what a sealed record adds, built from the same files as the regime packs. It says plainly that no law requires RiskRouter or any product. Questions and answers : nineteen short answers to what people ask before they write to us, each linking to the page that holds the detail. Search: a search box in every page’s header, and /search , over every page of the site down to its sections, with exact phrases in quotes and -word to exclude. The index is a file on this site, so what you type never leaves your browser. Press / to jump to it. The mark is now the icon everywhere: browser tabs, phone home screens, search results and any API address opened in a browser. The icon was redrawn so its three squares stay apart at every size, as they do in the header. The API’s own page at api.riskrouter.eu now looks like the rest of the site, with the same mark and icon, and lists every current route. The admin console uses the same icon. 29 September 2026 Agent adapters : each run of an AI agent becomes one evidence record, with its tool calls, model calls, handoffs, guardrails and graph nodes as steps, from a callback handler for LangChain and LangGraph and a tracing processor for the OpenAI Agents SDK, in Python and JavaScript. Steps keep a SHA-256 of the text they handled, not the text. An MCP server gives any MCP client a record_decision tool, whose records say they are the agent’s own statement. Tested against the real frameworks on every change. The recorders and adapters are licensed Apache-2.0 (those packages only; the rest of the source is not licensed), ready for PyPI and npm as riskrouter-recorder . The evidence log’s checkpoint key is published ( anchors/checkpoint/log.vkey ), so /tlog/evidence-v2/checkpoint now serves a signed C2SP checkpoint. Its private half was generated straight into the API’s secret store and exists nowhere else. No witness of the public network cosigns it yet. SCITT : the log registers IETF SCITT Signed Statements that are hash envelopes, signed with a key the distributor registered, and returns RFC 9942 COSE Receipts that any COSE library can check ( POST /api/v2/evidence/statement , GET /api/v2/evidence/receipt ). Only the statement’s digest is kept; the artifact never comes here. Verified in our tests by pycose, an independent implementation, and by both of our verifiers. Nothing frozen changed. Drop-in recorders for Python and Node: a logging handler, a decorator or function wrapper, and OpenTelemetry span processors that turn the decision logs a team already writes into evidence. Each record and its salt stay in a journal on the customer’s side, only the digest is sent, and nothing is marked recorded until the log says so. No dependencies; tested against the real engine and the real OpenTelemetry SDKs on every change. The FSMA replied to our question of 19 September about the boundary of insurance distribution. It restated the legal definitions and left the analysis of whether registration is needed to us, with a specialised legal adviser if need be; it did not rule on our model. Summarised on /evidence , which no longer waits for an answer. 28 September 2026 The evidence log now also speaks the C2SP transparency-log formats that the public witness network uses: a signed checkpoint at /tlog/evidence-v2/checkpoint for the same tree as the v2 head, and hash tiles beside it, so anyone can mirror the tree and compute any proof without our API. Entry bundles are not published. Checked against litewitness, the reference witness, in CI, and by both verifiers. The checkpoint key is not published yet, so no checkpoint is served until it is, and no witness of that network cosigns our log yet. Specification Witnesses : anyone can now run a witness of an evidence log on their own account, as a Cloudflare Worker, in a fork of the verifier repository on GitHub, or on a small server, with a key only they hold. It co-signs a head only after checking the log never rewrote history, pins each log’s keys on first sight, and keeps the evidence for good if a log contradicts itself. Its web side only serves what it has stored. A public registry at /registry.json lists every log and every witness, from files in the repository; a self-hosted instance can witness every listed log, and its own, by switching on one service. Today the registry lists one log, ours, and no witnesses. The engine can run in a customer’s own account: the same code on their own Cloudflare and Supabase, or anywhere containers run (PostgreSQL, PostgREST and the API). A self-hosted instance signs with its own key, holds its own data and calls nothing of ours, and it hands out no sandbox keys unless its operator switches that on. Built and checked end to end from nothing every week in CI. Running it needs the source and a licence, agreed in writing. Continuity 27 September 2026 RFC 3161 time on every signed head: each hour, every new evidence head and ledger attestation is sent to two independent time-stamping authorities (DigiCert and Sectigo), and their signed tokens are kept in anchors/tsa/ beside the Bitcoin anchors. The token binds the exact payload we signed; both verifiers check it offline, and /verify counts only tokens that verify. These are not qualified eIDAS time stamps, and every page and verifier says so. Specification Regime packs : what to record, rule by rule, so the log’s proof answers the question a supervisor will ask. Five packs, for insurance distribution (IDD), MiFID II suitability, the AI Act’s logging and human oversight, GDPR Article 22 and DORA incidents, each field mapped to its article with a link to the text. Published as data at /packs/.json . A record has one canonical form (RFC 8785, specification ), so a supervisor holding the record and its salt can recompute the digest in any language, and a bundle (record, salt, proof) checks offline with either verifier. The conformance suite gains the record cases. Nothing changed in the API: the log still accepts any kind. Signed leaves : a distributor can sign each claim with its own P-256 key, registered once at POST /api/v2/evidence/keys and served to anyone at GET /api/v2/evidence/keys . The signature goes inside the leaf (a new leaf version, v3, beside v2 in the same tree), so a proof now shows that the distributor asserted the decision, not only that we sealed it. Verified before anything is written; a claim that does not verify records nothing. Optional per entry. Both verifiers and the conformance suite check the client signature; the Python kit gains a standard-library signer. A conformance suite for anyone implementing the evidence formats in their own product: it grades an implementation in any language against the specification’s test vectors and against proofs that have been deliberately broken, checks the exports and proofs the product writes, and gives a result file that is the implementer’s own to publish. Ships in the kit at /kit/conformance/ ; the reference code passes all 46 cases. The evidence log’s Merkle tree is now kept in the database and maintained on every append, so a head or a proof reads a handful of stored subtree roots instead of every leaf, and the size ceiling on those routes is gone. Signed heads are stored once per tree size and the database refuses a head whose root is not the tree’s own. Nothing frozen changed: the specification , its vectors and both verifiers are untouched, and the stored-node fold is held equal to the leaf fold by tests in JavaScript and in SQL. POST /api/v2/evidence/batch : up to 500 digests in one transaction, in order, all or nothing, under the same ceilings per entry. API reference . Usage : how much is recorded and by whom, counted live from the ledger by a new public endpoint, GET /api/v1/usage , which returns nothing but numbers and week dates. The figure it leads with is entries recorded by keys that are not ours. Below it, how many independent witnesses and conformance results published by others exist, from the repository at build time; today both say none yet. Every claim, and where to check it : one page for a security review, a regulator or an investor, each claim with its artefact and who other than us can check it, and a plain no where the answer is no. How old the record is : the first anchored head, the earliest Bitcoin block it is in, how many heads are anchored and how many independent witnesses co-sign, computed from the published anchors every time the site is built and never typed into a page. Also on the home page and as proof-of-age.json . Where a figure is zero it says none yet. 24 September 2026 A new look: paper, ink and typefaces served from this site, set like a document rather than a product launch. The home page shows the last three ledger entries exactly as they were anchored. A page for broker-software vendors : what one integration gives every broker on a package. Check your setup : paste a key and see whether it is recording, whether your chain links up and whether we signed its head. Verifiers now choose the signing key by its id, so attestations saved before a future key rotation keep verifying. Every page is checked against WCAG 2.1 AA on every change; code blocks can now be scrolled with the keyboard. A security questionnaire, answered : the questions a vendor-risk team sends, each answer linked to its evidence, with a plain no where the answer is no. A status page that checks the API, the ledger and the evidence log live from your browser, and shows no uptime history until one has been measured. The API names the commit it is running ( build.commit on /api/v1/health ), and a bill of materials shows that no third-party package runs in production. First restore drill: a backup of the ledger was restored and matched the head anchored in Bitcoin. Continuity Backups are now weekly and automatic: each one is restored into a fresh database and checked against the anchored head, then kept encrypted on GitHub for 30 days, which is outside the EU. Sub-processors Fixed: a refused contact-form write logged the database’s whole error body, which can contain the sender’s name and email. Error logs now keep only the error code and message. Fixed: checking an export against a head recorded earlier said history has been altered whenever entries had been added since, which is always. A recorded head now matches when it is any earlier head of the chain, and the check says up to which entry history is unchanged. Same fix on /verify , in tools/verify-ledger.mjs and in the Python verifier. Fixed: when the ledger could not be read, /verify showed 0 entries and its copy button put the error message on the clipboard as if it were a hash. It now shows no count and offers nothing to copy until a real head has arrived. 23 September 2026 Evidence log v2: record a fingerprint of any regulated decision, not only a quote. The record stays with you; only its salted SHA-256 is sent. Entries sit in an RFC 9162 Merkle tree with signed heads, inclusion and consistency proofs. v1 is unchanged. API reference An open specification of every byte the evidence commits to, with test vectors and a second, independent verifier in Python. A witness tool anyone can run to check our heads and co-sign them. There are no independent witnesses yet. How it works An integration kit for broker-software vendors: Python, PHP, C#/.NET and Java, standard library only, plus a reference broker app, all tested against the real Worker on every change. The 13 September head is timestamped in Bitcoin (block 967830 and later), via three OpenTimestamps calendars. Heads are now anchored weekly by an automated workflow. Verify Single-entry proofs: show one quote to a regulator or a customer without revealing any other. Verify Every API error links to the row of the API reference that explains it; ten codes that had no row now do. A Postman collection generated from the OpenAPI spec, and a try it panel on the API reference . Fixed: a browser on riskrouter.eu could not send an API key to the API, so the live console could price but never record. Security headers on the site and the API, a hash-based Content-Security-Policy, security.txt and a disclosure policy . A continuity and exit plan , with the facts a DORA register of information needs. Three guides for distributors, a share image per page, and the ledger’s live head on the home page. Campaign links are counted without cookies, storage or third parties. What is counted 22 September 2026 Self-serve sandbox keys: take one on screen with nobody in the loop. Get a key Idempotency-Key on recorded quotes: a retried request can never create a second ledger entry. An OpenAPI 3.1 description of the API, kept identical to the running routes by a test. Check your own export in the browser on /verify , with nothing uploaded. Fixed: a keyed quote whose ledger write failed still reported attribution.recorded: true . 20 September 2026 Distributors can export their own entries, the chain they sit in and the signed head, and verify it without us. The public verifier repository went live. Heads first submitted to OpenTimestamps calendars. A break it yourself demonstration of the chain on /verify . Rate limit on the export, the one route that had none. 19 September 2026 The platform moved to riskrouter.eu, with a published contact address. 13 September 2026 Attestations of the ledger head are signed (ECDSA P-256), so a head someone saved cannot be disowned. Ledger writes are attributed to a distributor, and the attribution is inside the entry’s hash. 12 September 2026 The ledger becomes tamper-evident: every entry is SHA-256 hash-chained to the one before it. First version of the engine, the audit ledger and the demo console. Rating matrix 2026.09.1 . ## Open evidence specification URL: https://riskrouter.eu/spec Specification version 1.0 23 September 2026 Open evidence specification Every byte RiskRouter’s evidence commits to, written down so that anyone can check it without us, and anyone can build a second implementation. Two already exist that share no code: the JavaScript verifier and a Python one, held to identical verdicts by the repository’s tests. Anyone may implement this specification without asking us. 0 Conventions Conventions Hashes are SHA-256, written as 64 lowercase hexadecimal characters. Strings are UTF-8. Fields are joined with | , with no spaces and no escaping; no field may contain | . Timestamps inside hashed strings are UTC, YYYY-MM-DDTHH:MM:SS.ffffffZ , six fraction digits. A reader that receives +00:00 , a space instead of T , or fewer digits must normalise to that form first. Signatures are ECDSA over P-256 with SHA-256, encoded as the 64-byte r||s (IEEE P1363), base64. Public keys are JWK. The published key is in the public verifier repository , key id dd4b4b394c95586a , and stays there after any rotation. Frozen means: changing it would invalidate evidence people already hold, so it will never change within a version. 1 v1 quote ledger The quote ledger: a hash chain 1.1 Canonical form (frozen) chain_index|id|created_at|active_vertical|components|premium|compliance_status|matrix_version|distributor_id|prev_hash components : every component key in ascending order, as key=true or key=false , joined with commas. A value is true only if it is the JSON literal true . premium : exactly two decimals, such as 2.00 . matrix_version and distributor_id : empty when absent. row_hash = SHA-256 of the canonical form. The first entry’s prev_hash is 64 zeros; every other entry’s is the previous entry’s row_hash . The last row_hash is the head . 1.2 Attestation (frozen payload) riskrouter-ledger-attestation|v1|as_of|entries|head_hash The signed statement that the ledger had entries entries and that head at as_of . A verifier rebuilds this payload from the attestation’s own fields; it never trusts a signed_payload field alone. 1.3 Export and single-entry proof An export ( riskrouter-ledger-export|v1 ) carries the holder’s entries in full, the (chain_index, row_hash, prev_hash) of every entry, and the signed attestation. A single-entry proof ( riskrouter-entry-proof|v1 ) carries one entry, the links from it to the head, and the attestation. What these prove, precisely: the holder’s entries are rebuilt from content; other entries are followed by digest only and bind because anyone recomputing the full ledger must reach the signed head. A rebuilt ledger is caught by comparing with a head recorded earlier, which is why heads are anchored (section 4). 2 v2 evidence log The evidence log: digests of any regulated decision, in a Merkle tree 2.1 What the client sends The client hashes its own record and sends only record_digest and a kind tag ( ^[a-z0-9][a-z0-9.-]{0,39}$ ). The record never leaves the client. The client must salt the record. Hash a random value of at least 128 bits together with the record, and keep both. A digest of a guessable record, such as approved , can be confirmed by anyone who guesses it. The salted construction this specification recommends is SHA-256(salt || record) , but any construction the client can reproduce is valid: the log commits to the digest, not to how it was made. 2.1b Canonical record and bundle (frozen) How the record is hashed is the client’s choice, but a record another party must be able to re-hash, such as one written to a regime pack , uses this construction: record = a JSON object; keys ^[a-z][a-z0-9_]{0,63}$ at every level; values are strings (valid Unicode), integers within (2^53 1), true, false, null, arrays and objects, nested at most 32 deep; no fractions (money is integer cents) canonical = RFC 8785 (JSON Canonicalization Scheme) of the record record_digest = SHA-256(salt || UTF-8(canonical)), salt 16 to 64 random bytes as lowercase hex bundle = { "format": "riskrouter-record-bundle|1", "record", "salt_hex", "proof" } A record outside the profile is refused rather than coerced. A bundle is intact when the record and salt produce the entry’s record_digest , the record’s kind is the entry’s, and the proof verifies as below. The vectors carry records chosen for the places two languages differ (escapes, astral characters, key order, edge integers) and records that must be refused. 2.2 Leaf (frozen) leaf string = riskrouter-evidence-leaf|v2|leaf_index|created_at|distributor_id|kind|record_digest leaf hash = SHA-256(0x00 || leaf string) leaf_index counts from 0 with no gaps. created_at is set by the log, never by the client. Every entry carries leaf_version , 2 or 3; a verifier rebuilds the leaf string for the version it sees. 2.2b Signed leaf (frozen, v3) A v2 leaf proves that the log sealed a digest at a time. It does not prove that the distributor asserted anything: for that, the distributor signs its own claim, and the signature goes inside the leaf, so it cannot be swapped after the fact. Optional per entry; an unsigned entry is a v2 leaf exactly as above. Both versions sit in the same tree under the same head. claim payload = riskrouter-evidence-claim|v3|kind|record_digest|signer_key_id|claimed_at signed by the client: ECDSA P-256 over SHA-256, IEEE P1363 (r || s), base64 leaf string = riskrouter-evidence-leaf|v3|leaf_index|created_at|distributor_id|kind|record_digest|signer_key_id|claimed_at|client_signature leaf hash = SHA-256(0x00 || leaf string) signer_key_id = first 16 hex characters of SHA-256(JSON [x, y] of the public JWK), as a witness id is derived claimed_at = the client's own timestamp, YYYY-MM-DDTHH:MM:SS.ffffffZ, exactly as it was signed The client signs only what it knows before sending; leaf_index and created_at remain the log’s. The log verifies the signature before recording and refuses a claim that does not verify, with nothing written; the database then commits to the signature as presented, and every verifier checks it again. The public key is registered once ( POST /api/v2/evidence/keys ) and served to anyone ( GET /api/v2/evidence/keys?key_id= ); a proof of a v3 leaf carries it as signer_public_key . The signer should publish the same key under its own control , exactly as a witness does, so that the client signed it is not the log’s word alone. A key id belongs to one distributor forever; registering a new key never removes an old one, so leaves signed before a rotation stay verifiable. What a v3 leaf proves: this distributor, holding this key, asserted this digest and this kind at the time it claimed, and the log sealed that assertion at created_at in a tree whose head is signed. What it does not prove: that the record behind the digest is true, or that the key was not stolen. 2.3 Tree RFC 6962 / RFC 9162, unchanged: node hash = SHA-256( 0x01 || left || right), with the split at the largest power of two smaller than the number of leaves; the root of the empty tree is SHA-256 of the empty string. Inclusion and consistency proofs are the RFC 9162 section 2.1.3 and 2.1.4 constructions, verified by the algorithms given there. The implementation is checked against RFC 6962’s own reference roots. 2.4 Signed tree head (frozen payload) riskrouter-evidence-head|v2|tree_size|root_hash|timestamp Signed with the same key as v1 attestations. A verifier must take tree_size and root_hash from the same signed head : an inclusion proof does not bind the tree size on its own. A head with no key bound is returned unsigned and says so; it is never given a signature it does not have. 2.5 Endpoints POST /api/v2/evidence , POST /api/v2/evidence/batch , GET /api/v2/evidence/head , GET /api/v2/evidence/proof , GET /api/v2/evidence/consistency , and for signed leaves POST and GET /api/v2/evidence/keys , described in the API reference and openapi.json . A consistency proof is checked against the root of a head the verifier saved, never a root the log supplies. 3 Witnesses Independent witnesses A witness is anyone who is not the operator. Each time it runs it fetches the current signed head, checks the operator’s signature, requests a consistency proof from the last head it saved, and checks that proof against the root it saved. Only if every check passes does it co-sign: riskrouter-evidence-cosign|v2|witness_id|tree_size|root_hash|cosigned_at If a check fails, the witness holds two heads, both signed by the operator, that cannot both be true. That pair is evidence of a rewritten history that the operator cannot disown, produced by someone the operator does not control. The reference witness is tools/witness.mjs ; it saves the pair and exits with status 2. The portable witness in witness/ of the verifier repository does the same for many logs at once, on Cloudflare Workers, Node or GitHub Actions. Its cosignature file is the same format, with one added member, log ( { id, api } ), which a verifier ignores. It pins a log’s head-signing keys the first time it sees them and raises an alarm if a later list drops or changes one; an alarm is never overwritten, and the witness stops co-signing that log. It serves, read-only, /public-key.json , /logs.json , /cosignatures//latest.json and /alarms/.json . Logs and witnesses are listed at /registry.json ( riskrouter-witness-registry|1 ); a witness is listed only once it publishes its key under its own control. There are no independent witnesses yet. How to become one: /witnesses . The same log in the C2SP formats The v2 tree is also published in the formats the public witness network speaks, so that witnesses who have never run our code can check it: c2sp.org/signed-note , tlog-checkpoint , tlog-cosignature and tlog-tiles . Two things are frozen, on the same terms as the forms above: the origin, api.riskrouter.eu/tlog/evidence-v2 , and the checkpoint text, three lines and no extension lines: api.riskrouter.eu/tlog/evidence-v2 The root is the same 32 bytes as root_hash in the v2 head, in base64 instead of hex, and one read of the tree gives both. The note is signed with the log’s Ed25519 key (signature type 0x01 ), whose key name is the origin and whose key ID is the first four bytes of SHA-256(name || 0x0A || 0x01 || public key). That is a separate key from the P-256 head-signing key, published as a vkey in anchors/checkpoint/log.vkey . A checkpoint is served at GET /tlog/evidence-v2/checkpoint only when that key is bound; otherwise the answer is 503 , never an unsigned note. Witnesses of the network return cosignatures of type 0x04 (cosignature/v1, Ed25519 over cosignature/v1\ntime \n and the checkpoint text), and we keep each one that verifies in anchors/checkpoint/cosigned/ . Tiles of hashes are served at /tlog/evidence-v2/tile//[.p/] , so anyone can mirror the whole tree and compute any proof without our API ( node tools/checkpoint.mjs mirror ). Entry bundles are not published: every leaf names a distributor and a kind, and a distributor holds its own entries with their proofs. Both verifiers check checkpoints and cosignatures; spec-vectors.json carries a checkpoint and a cosignature made with the RFC 8032 test keys, and the conformance suite derives cases from them. 3b SCITT Signed Statements and COSE Receipts The log also serves as a Transparency Service in the sense of the IETF SCITT architecture (draft-ietf-scitt-architecture), returning receipts as defined by RFC 9942 (COSE Receipts). Registration, POST /api/v2/evidence/statement , applies the policy riskrouter-scitt-profile|1 : a COSE_Sign1 signed ES256 with a key the caller registered ( kid = its 16-hex id as UTF-8), CWT claims iss and sub (text, neither an email address), and a hash envelope (draft-ietf-cose-hash-envelope: protected 258 = -16, a 32-byte payload), so the artifact never reaches the log. What the log keeps is one v2 leaf of kind scitt.statement whose record_digest is: SHA-256( 0xD2 0x84 || bstr(protected) || 0xA0 || bstr(payload) || bstr(signature) ) that is, the statement re-encoded with an empty unprotected header. A receipt ( riskrouter-scitt-receipt|1 ) is a COSE_Sign1 signed ES256 with the head-signing key ( kid = its key id), vds 395 = 1 (RFC9162_SHA256), vdp 396 holding one inclusion proof [tree_size, leaf_index, [hash, ]] at label -1, and a detached payload: the root. Its protected header carries CWT claims ( iss , sub = the statement digest, iat ) and riskrouter-leaf = [leaf_index, created_at, distributor_id, kind] . To check one: rebuild the v2 leaf string from those fields and sub , walk the proof to a root, and verify the signature over ["Signature1", protected, h'', root] with our published key. Both verifiers do this, and pycose, an independent COSE library, verifies our receipts in our tests. The statement itself stays with its issuer: we keep its digest only, which is where we depart from the architecture draft, deliberately (rule 15). spec-vectors.json carries a statement digest and a receipt’s signed bytes. 4 Anchoring Anchoring heads in time Signed v1 heads are committed to OpenTimestamps calendars and upgraded to Bitcoin attestations; the 13 September 2026 head is in block 967830 and later. This bounds when a head existed, from above. It says nothing about the moment of each entry before it. 4.1 RFC 3161 time-stamp tokens (frozen imprint) Every hour, each new signed head (v2) and each new signed attestation (v1) is sent to the RFC 3161 time-stamping authorities listed in anchors/tsa/authorities.json . The token binds exactly the payload we signed: message imprint = SHA-256(UTF-8(signed payload)) hashAlgorithm sha256 signed payload = riskrouter-evidence-head|v2|tree_size|root_hash|timestamp or riskrouter-ledger-attestation|v1|as_of|entries|head_hash file = anchors/tsa/..json { "format": "riskrouter-head-timestamp|1", subject, signed, signature, payload, tsa: { id, name, url, qualified, trusted_list }, token (DER, base64), gen_time, requested_at } A verifier rebuilds the payload from the head in the file, checks our signature on it, then the token: the imprint, the signed attributes (content type and message digest), the authority’s signature with the certificate the token carries, that the certificate is for time-stamping and valid at genTime , and the chain the token carries, whose root it compares with the root the authority publishes ( openssl ts -verify -data payload -in token -token_in -CAfile root.pem does the same). Both verifiers do this offline. None of the authorities used today is a qualified eIDAS time-stamping service : a token is evidence of time from an independent authority, without the presumption of accuracy that a qualified time stamp carries under Article 41(2) of Regulation (EU) No 910/2014. A file calls a token qualified only when its authority is listed with its entry on the EU Trusted List. 5 Test vectors and implementations Check your implementation spec-vectors.json holds deterministic inputs and expected outputs for every frozen form above: timestamp normalisation, a v1 canonical form and row hash, the attestation payload, eight v2 leaves and the roots of every prefix, an inclusion proof, a consistency proof, a head payload, a cosignature payload, and a C2SP checkpoint and cosignature with their Ed25519 signatures. It is regenerated from the reference code and both verifiers must agree with it before any change ships. JavaScript : tools/verify-ledger.mjs , tools/merkle.mjs , tools/witness.mjs (Node, standard library). Python : riskrouter_verify.py (standard library only, including its own P-256 and Ed25519 checks). In the browser : the checker on /verify , which sends nothing anywhere. Run the conformance suite The conformance suite turns those vectors into cases an implementation in any language can answer, adds proofs that have been deliberately broken and must be refused, and grades the answers. It ships with the reference code and the vectors in /kit/conformance/ , needs only Node, and contacts nothing. node conformance.mjs cases > cases.json # one JSON object per frozen form, with the expected answer # your implementation answers each case: { "": } node conformance.mjs grade answers.json --name "Your product 12.4" > result.json # or drive a command that reads one case on stdin and prints its answer: node conformance.mjs run --command "python3 my_impl.py" --name "Your product 12.4" > result.json # and check what your product produced: an export, an entry proof, an evidence proof, an evidence pack node conformance.mjs artefacts ./evidence/ --key signing-key.json > artefacts.json The result file is the implementer’s own statement: that this implementation, on this date, answered these cases as the vectors say, named by the vector set ( riskrouter-spec-vectors|1 ) and the digest of the cases, so anyone can run the same cases again. RiskRouter certifies nothing and nobody. An implementation that passes needs no permission from us to say so, and no relationship with us to keep it true: the vectors and the suite are published, and both are free. A defect in this specification, or a disagreement between it and any implementation, is a bug we want to hear about: security explains how to report one. ## Service status · RiskRouter URL: https://riskrouter.eu/status Status checked live, from your browser Service status Each line below is checked now, by your browser, against the live API. Nothing on this page is typed in by us, so it cannot say all systems operational while something is down. Right now What answered, and what it said Check Result Detail API checking Quote ledger reachable from the API checking Signed ledger head checking Signed evidence-log head checking Running build checking Check again What degraded means here. If the ledger cannot be reached, quotes are still priced but nothing is recorded, and every response says recorded: false . We never report a record that was not written. That is the designed safe state, not a hidden one. History Measured from outside, 30 September 2026 to 1 October 2026 GitHub Actions, which runs on none of our infrastructure, probes the website and the API about twice an hour and keeps every answer. The API counts as up only when it answers OPERATIONAL ; degraded, meaning priced but not recorded, is counted separately. These are the last 30 days, as of when this page was built (2026-10-01 19:18 UTC). Check Up Rounds up Degraded Down API and ledger 100.00% 9 of 9 Website 100.00% 9 of 9 9 rounds. For 17.1 hours in 3 stretches GitHub ran no probe; that time is not measured, and not counted as up. No round failed. The same figures, as JSON: /uptime.json . Incidents and anything that affected recorded evidence are written up on the changelog . How we would recover from losing the database, and when we last proved it by restoring a backup, is on the continuity page . Dependencies What we depend on, and their own status pages Provider What stops if it stops Their status Cloudflare The site and the API cloudflarestatus.com Supabase (Frankfurt) Recording; pricing continues and says so status.supabase.com Evidence you have already saved does not depend on either: an export, a proof or an attestation verifies offline, with no call to us. How to check one . ## Security questionnaire, answered URL: https://riskrouter.eu/security-questionnaire For vendor-risk and security teams answers as of 23 September 2026 Security questionnaire, answered The questions a bank’s or insurer’s vendor-risk team sends, answered before you send them. Every answer links to something you can check: a page, a live endpoint, a published file, or a test in our repository. Where the answer is no, it says no. If your own questionnaire asks something that is not here, send it to anil@riskrouter.eu and the answer will be added here for the next team too. Read this first Three facts that frame every answer RiskRouter is a validation build operated by one person. There is no legal entity yet, no staff, and no contract yet. Answers below describe what is in place now, not what a larger company would have. It holds almost nothing worth stealing. Quotes carry no personal data; the v2 evidence log holds only SHA-256 digests; API keys are stored only as digests. The one table with personal data is contact-form enquiries, deleted after twelve months. Your evidence does not depend on our security. A ledger export or proof you hold verifies offline, against a key we published and heads anchored in Bitcoin. If we were breached, a rewrite of history would be detectable by you, without us. How . Evidence marked repository lives in our source repository, which is private today. Any file named here is shown to a prospective customer on request. 1 Data What data, where, for how long Question Answer Evidence Do you process personal data on our behalf? No, by design. A quote is a vertical and a set of true/false options. Anything else in a request is dropped before storage. The evidence log accepts only a 64-character digest and a short tag. /trust ; repository: tests/pii.test.mjs sends personal data in every field and asserts none is stored What personal data do you hold at all? Contact-form enquiries (name, email, message), and the administrator’s own email address in the admin audit log. /privacy Retention Enquiries are deleted after 12 months by a scheduled database job, running daily. Ledger and evidence entries are kept permanently; that is their purpose, and they hold no personal data. /privacy ; repository: schema.sql , purge_expired_contact_enquiries() Where is data stored? Supabase, eu-central-1 , Frankfurt, Germany. /trust , /continuity Where is it processed? Not only in the EU. Requests are handled by Cloudflare at the location nearest the caller, which may be outside the EEA. Nothing is stored there. EU-only processing would need Cloudflare’s regional services, which we do not have. /trust , /privacy Encryption in transit Yes. HTTPS only, with HSTS on the site. The Workers reach the database over HTTPS. Response headers of any page ( Strict-Transport-Security ) Encryption at rest Provided by the database host, Supabase, under its own security documentation. We add no application-level encryption, and have not independently verified theirs. Supabase’s documentation Can you delete our data on request? Enquiries: yes. Ledger and evidence entries: no, never , because an audit trail that can be deleted is not one. That is why they may hold no personal data, and why a self-serve key must acknowledge it before recording. /privacy , /integrate 2 Access control Who can reach what Question Answer Evidence Who has administrative access? One person, the operator. No one else holds production access. /continuity How is the admin console protected? Cloudflare Access in front, restricted to one email address; the Worker then verifies the Access signature itself rather than trusting a header, and checks the address against its own list. Writes are accepted only from the console’s own origin. Repository: admin-worker.js , tests/admin.test.mjs Is multi-factor authentication enforced? Not claimed. The minimum configuration is a one-time code sent to the allowed address. Stronger factors depend on the identity provider linked to Access, and we do not claim one here. — What can an administrator do? Five things and no more: create a distributor, suspend or reactivate one, issue a key, revoke a key, set an enquiry’s status. There is no path from the console to a quote, a premium, a ledger entry or the schema. Every action is one database transaction that also writes an append-only audit row. Repository: CLAUDE.md rule 8, schema.sql , tests/admin.test.mjs How are your customers authenticated? A per-distributor API key, shown once, stored only as its SHA-256, revocable immediately. An unknown, revoked or suspended key is refused with 401 and nothing is written. /docs ; repository: tests/worker.test.mjs Can one customer read another’s records? No. An export carries the caller’s own entries in full and only the hashes of anyone else’s, which is what lets the chain be checked; an evidence proof for another distributor’s entry answers exactly like a missing one. Row-level security is forced on every table and the public roles have no grants. Repository: tests/evidence.test.mjs , tests/schema.test.sql Single sign-on for our staff? No, and there is nothing to sign in to. Customers integrate with keys; there is no customer console. — 3 Integrity Can records be altered? Question Answer Evidence Can a record be edited or deleted? No. Database triggers refuse UPDATE and DELETE on the ledger, the evidence log and the admin audit log, for every role including our own service role; the evidence log also refuses TRUNCATE by trigger. Repository: schema.sql , tests/schema.test.sql Would a rewrite of history by you be detected? Yes, by you. Entries are hash-chained (v1) or Merkle-logged (v2); heads are signed with a published key and anchored in Bitcoin through OpenTimestamps. A rebuilt history produces a different head than one you or a witness saved. /spec , /verify Can we verify without you? Yes. Two independent verifiers, JavaScript and Python, standard library only, plus an in-browser checker that sends nothing. /spec , Python verifier Do independent parties co-sign? Not yet. The witness tool exists; no independent witness runs it today. /spec#witnesses 4 Development and change How the code is built and shipped Question Answer Evidence How do changes reach production? Every push to main runs the unit, schema, browser and integration-kit test suites; the deploy job runs only after all of them pass. The running commit is published, so you can see whether production came from that path. /status , GET /api/v1/health ( build.commit ) Is every change reviewed by a second person? No. There is one developer. Review is by automated tests, several of which enforce the security rules mechanically (for example, that each Worker can reach only its named destinations). Repository: tests/isolation.test.mjs Third-party code in production None. The Workers import only our own files; the build fails if that ever changes. Build and test tools are listed separately and never deployed. /sbom.json (CycloneDX) Dependency updates Dependabot watches the build tools and CI actions weekly. The deploy tool is pinned to one version. Repository: .github/dependabot.yml , package.json Web application protections A hash-based Content-Security-Policy on every page (no inline script runs unless its hash is listed), HSTS, frame denial, no third-party scripts, per-address rate limits on the API, and database-enforced write ceilings that hold even if the API is bypassed. /security ; response headers Secrets management Credentials live only in Cloudflare Worker secrets and GitHub Actions secrets. None is in source code; tests fail if a Supabase URL or key appears in a Worker, or reaches a response. Repository: tests/isolation.test.mjs , tests/worker.test.mjs Penetration test None. If you need one before a pilot, it is a reasonable condition to agree. /security API change policy The formats evidence depends on are frozen permanently. Every change is listed in the changelog, and the contract terms we offer give at least 90 days’ written notice before we remove or change anything you rely on. /spec , /changelog , /dora 5 Logging, incidents, continuity When something goes wrong Question Answer Evidence What is logged? Cloudflare’s request logs for the Workers, and our own error lines when a write is refused: the HTTP status and the database’s error code and message, never a credential and never the rejected row. (Checking this answer found that a refused contact-form write logged the database’s whole error body, which can contain the sender’s name and email. Fixed on 23 September 2026, with a test.) Every administrative action is in an append-only audit table. Repository: worker.js , tests/pii.test.mjs , schema.sql ( admin_events ) Monitoring and alerting No external uptime monitor and no 24/7 on-call. The API reports its own state honestly (it probes the database rather than trusting its configuration), and /status shows it live. /status What happens when the database is unavailable? Quotes are still priced; nothing is recorded, and every response says recorded: false . A failed write is never reported as a success. /docs ; repository: tests/worker.test.mjs Incident response Written runbooks for incidents, leaked credentials (each secret, with what its holder could and could not do), key rotation and restore. Our runbook sets notification of affected distributors within 24 hours of a critical incident; that becomes a contractual commitment only in a contract. Repository: docs/runbooks/ (shown on request) Backups No managed backups. The database runs on a plan that keeps none. We take our own every day, automatically, and keep each for 90 days on GitHub, encrypted (AES-256) before upload with a passphrase GitHub does not hold. /continuity ; repository: .github/workflows/backup.yml Has a restore been tested? Yes, every day, automatically, since 23 September 2026; every run so far has passed. All entries restored; the restored head matched the head anchored in Bitcoin; the restored ledger still refused edits and deletions. /continuity ; repository: docs/drills/ , tests/restore-drill.test.mjs Recovery time and point objectives (RTO / RPO) None committed. Loading a backup takes under a second at today’s size; recovery time is dominated by detection and repointing. Data recorded after the last backup would be lost with the database. /continuity Exit plan if you stop Documented: what you keep, what stops, the steps to leave, and facts for a DORA register of information. /continuity Capacity, measured Load tested on every change against the self-hosted stack, not production: 600 evidence entries a minute across the log (864 000 a day) and 60 requests a minute per caller address, both held exactly and refused with a clean 429; batches of 50 recorded in about 22 ms; no server error, and every accepted entry was a leaf. Repository: docs/load-test.md , tools/loadtest.mjs DORA Article 30 contract terms Each required provision, the clause we offer, and what is in place today. Proposed until a legal entity exists. /dora 6 Third parties Sub-processors and suppliers Question Answer Evidence Sub-processors Cloudflare (runs the site and API), Supabase (database, Frankfurt), GitHub (encrypted daily backups, outside the EU), Microsoft (the mailbox behind our published address). That is the complete list. /privacy What can the API contact? Exactly one destination: the database. It contacts no carrier, bank, payment processor, analytics or advertising service. A test fails if a new destination is added. /trust ; repository: tests/isolation.test.mjs Certifications None. No ISO 27001, no SOC 2. Our providers publish their own; that does not make us certified, and we do not say it does. /security Insurance (professional indemnity, cyber) None yet. — Regulatory status Not a registered insurance intermediary and not an insurer. RiskRouter is software for licensed distributors and sells no cover. /compliance Report something Found a problem, or an answer that is wrong? Security reports: /security and security.txt . An answer on this page that is no longer true is a bug of the same kind; tell us and it will be corrected here and on the changelog . ## For broker-software vendors URL: https://riskrouter.eu/for-software-vendors For the companies that build broker-management software For broker-software vendors A broker who is asked what they advised a customer in August, and why, needs to show a record and show that it has not been changed since. You integrate RiskRouter once, and every broker using your package can do both. The customer file stays in your product; only a fingerprint of it reaches us. What changes for your brokers What a broker on your package gets A fixed record of the advice When the broker saves a demands-and-needs note, your software records a salted SHA-256 of it with us. From that moment the note cannot be altered without the fingerprint showing it. The note itself, and the customer’s name, stay in your database. Quotes they cannot be accused of editing Quotes priced through the API with the broker’s key are appended to a hash-chained ledger that the database refuses to edit or delete, and whose head is signed and timestamped in Bitcoin. An evidence pack per customer For one customer: the note, its salt and the two proofs. An inspector can check it offline with public tools, and learns nothing about any other customer. See the reference app that builds one . The work involved What the integration involves Take a sandbox key. No form and no contract: one click on /integrate . Run the example in your language. PHP, C#/.NET, Python and Java, each using only the language’s standard library: a client of 60 to 90 lines and a short demo. Each one prices a quote, records it, replays it safely, records a note’s fingerprint, exports and proves. The integration kit . Wire three calls into your product. POST /api/v1/quote with the broker’s key and an Idempotency-Key derived from your own quote id, so a double-click never records twice; POST /api/v2/evidence with the note’s fingerprint; and GET /api/v2/evidence/proof or GET /api/v1/ledger/export when a broker needs the evidence. Keep the salt with the note , in your own database. Without it nobody, including us, can link a fingerprint back to a person. The reference broker desk does all of it in one Python file of about 150 lines. Every example in the kit is run against the real API code on every change we make, so an example that stopped working would fail our own build. You can use the evidence log without our pricing at all: record fingerprints of the advice records your product already produces. The format is published , so you may also implement it yourself without asking us, and check that implementation with the conformance suite : it grades your code against the specification’s own test vectors and checks the exports and proofs your product writes, offline, and gives you a result file that is yours to publish. Nothing about it depends on us. What we do not do We will not compete with you or your brokers RiskRouter never contacts the customer, never handles a claim, never holds the carrier relationship and never stores the customer file. Those are fixed boundaries of the product, not a roadmap we have yet to reach. Your brokers stay yours. Working together What a first integrating vendor can expect No vendor has integrated yet, so there is no programme to join and no logo wall to be added to. Here is what we can promise today: Your developers talk directly to the person who builds the API. What you need goes to the top of what gets built next, if it fits the rules the product keeps. Your name appears on this site only once you have agreed to it in writing. No exclusivity and no lock-in: the specification is open and the verifiers are free. The sandbox is free. There are no commercial terms yet; we would agree them with you, not announce them to you. Before you commit For your security and compliance review The security questionnaire is answered in advance, with evidence and plain answers where the answer is no. The bill of materials shows no third-party package runs in production, status checks the service live, and the continuity plan sets out what your brokers keep if we stop and how a backup of the ledger is restored and checked: every day, automatically. Get a sandbox key Talk to us ## Usage in numbers · RiskRouter URL: https://riskrouter.eu/usage Usage counted live, from the ledger How much is recorded, and by whom Every figure on this page is counted from the quote ledger and the evidence log at the moment you load it, by your browser, from a public endpoint. Nothing here is typed in by us, so it cannot show traction we do not have. Where a number is zero, it says zero. Right now Entries, and who recorded them entries in both logs in the last 28 days recorded by keys that are not ours distinct keys recording, 28 days Count again The third figure is the one that matters. Everything else on this site can be produced by our own effort. An entry recorded with a key that is not ours means somebody outside decided the API was worth writing code against, ran it, and sent a key. Self-serve sandbox keys count as outside and are also shown separately below, because a key nobody had to ask us for is weaker evidence than a contracted one. Detail By log, and by origin of the key Figure Count Note Quote ledger (v1) entries Evidence log (v2) entries Entries by keys that are not ours of which self-serve sandbox keys Distributors with a key Twelve weeks Entries per calendar week Week starting (Monday) Quotes Evidence Not ours counting Adoption by people who are not us Witnesses and conformant implementations none yet independent witnesses none yet conformance results published by others Counted from witnesses/ and conformance-results/ in the repository when this page was built. A witness is listed only when it publishes its own key; a result only when its implementer publishes it themselves. Become a witness Run the conformance suite How this is counted What the figures mean, and what they do not Where the numbers come from GET /api/v1/usage , a public endpoint that counts the two logs on request and returns nothing but numbers and week dates: no identifier, no premium, no record. It is cached for five minutes at the edge. API reference . Ours Entries recorded with RiskRouter’s own validation keys, and entries that predate attribution. Everything else is not ours , including self-serve sandbox keys. What an entry is not Not a customer, not a policy, not revenue. It is one record sealed into a log. No cover is in force anywhere behind these figures; this is a validation build. Why publish it at all Because a number an outsider can fetch is worth more than a number on a slide, and because a small number said plainly is the only kind that can be believed when it grows. Every other claim we make, and where to check it . ## Every claim, and where to check it URL: https://riskrouter.eu/evidence Evidence for a security review, a regulator, or an investor Every claim, and where to check it This page exists so that due diligence takes an hour rather than a week. Each row is a claim we make somewhere on this site, the artefact that supports it, and who other than us can check it. Where the honest answer is nobody yet or no , the row says so. Nothing linked here needs an account, a call, or our cooperation. The record What the ledger and the evidence log prove Claim Check it at Who else can check Every recorded quote is chained; an altered, deleted or inserted entry is detectable /verify : the live head, and an in-browser checker for an export. Canonical form Anyone holding an export, with the public verifier , offline The head is signed, so we cannot later deny having published it Live attestation ; public key at /api/v1/ledger/pubkey and in the verifier repository Anyone, with verify-attestation.mjs or the Python verifier A signed head existed before a given date How old the record is : the anchors and their Bitcoin proofs, figures computed from the files at build time; proof-of-age.json Anyone with ots verify against the Bitcoin block The evidence log holds digests only, in an RFC 6962 Merkle tree, and never a record The specification , with test vectors ; the database refuses anything that is not a 64-hex digest Any implementer, with the vectors; any holder of a proof, with either verifier The formats are open and can be implemented and checked without us The conformance suite , in the kit at /kit/conformance/ Any implementer; their result is theirs to publish. None published by others yet Independent parties co-sign the log How witnesses work ; keys in witnesses/ No independent witness yet. The page says so rather than leaving it out How much is recorded, and by whom /usage , counted live from the ledger by your browser Anyone; GET /api/v1/usage is public The service What runs, and how it is kept running Claim Check it at Who else can check The API is up and the ledger is reachable, right now /status , checked live by your browser, with the history measured from outside by GitHub Actions about twice an hour; /uptime.json Anyone, on every page load What is deployed is what was reviewed build.commit on /api/v1/health names the commit CI deployed Anyone; the commit is on the deploying workflow’s run No third-party code runs in production The bill of materials , derived from the Workers’ own imports on every build Anyone reading the SBOM The API is documented as it runs OpenAPI 3.1 , held identical to the routes by a test; reference Anyone generating a client from it Backups exist, restore, and match the anchored head Continuity : what each drill checks; daily and automatic Our records; a customer can ask for the latest drill report A customer can leave with their evidence intact The exit plan ; the export format and the verifiers are public Any customer, by exporting today Security and data What we hold, and what we do not Claim Check it at Who else can check A quote holds no personal data; an evidence entry is a salted digest of a record we never see Data protection , what the client sends Any integrator, by reading what their code sends Where data lives, and every sub-processor Sub-processors and Trust : EU hosting, plus one encrypted daily backup copy kept 90 days on GitHub, outside the EU The list is complete; there is no second list How to report a vulnerability, and the headers every page ships with security.txt (RFC 9116), Security Anyone, with a scanner The answers a vendor-risk team asks for Security questionnaire, answered , each answer linked to its evidence Any reviewer Whether the browser ever computes a price It never does: pricing is server-side only; the rating matrix and its fingerprint are published per version Anyone, by comparing the API’s answer with the published matrix What we do not claim The plain answers Registration RiskRouter is not registered with the FSMA. In our own analysis it is not an insurance intermediary: it is software for licensed distributors. A written question about the boundary was sent to the FSMA on 19 September 2026, and the FSMA replied by email on 29 September 2026. It restated the definitions of insurance intermediary and insurance distribution in the Act of 4 April 2014, and said that whether an activity needs registration, and under which status, is for the business to analyse itself, with a specialised legal adviser if need be, because the FSMA does not know its business model. It did not rule on ours, and its emails state that they are not official information from the FSMA. The boundary is therefore still our own analysis, not the FSMA’s; this page will say when a legal opinion settles it. Regulatory position . Customers, carriers, certifications None. No customer, carrier, certification or testimonial appears anywhere on this site, because none exists yet. A vendor’s name appears only once they have agreed to it in writing. Cover No cover is in force anywhere behind this system. Every price is a simulation of a published rating matrix, and every page says so. Uptime No history is shown until an external monitor has measured one. Status . What would change this page A witness key, a conformance result published by someone else, a first outside entry on /usage , or a specialised legal opinion on the registration question. Each is a fact, not a promise, and each changes a row above from none yet to a number or a link. ## Regime packs: what to record, rule by rule · RiskRouter URL: https://riskrouter.eu/regime-packs Regime packs one proof, mapped to each rule What to record, rule by rule The evidence log proves that a record existed, unaltered, no later than a signed and anchored head. It does not know what the record is. A pack says, for one regime, which fields to put in a record so that the proof answers the question a supervisor will ask, and maps each field to the article it speaks to. The record stays with you; only its salted fingerprint is sent. Six packs are published, as data anyone can use without us. How it works A record, its fingerprint, and the bundle you hand over 1. Write the record A JSON object with the pack's fields, in your own system. Identify people and cases by your own references, never by name: the pack's reference fields refuse anything that looks like a name or an email. 2. Send its fingerprint Canonicalise it (RFC 8785, with the profile in the specification ), hash it with a random salt, and send only the digest and the kind to POST /api/v2/evidence . Optionally sign it with your own key, so the leaf carries your signature too. 3. Keep three things The record, the salt, and the proof the API gives for the entry. Together they are a bundle : riskrouter-record-bundle|1 . 4. Hand over the bundle Anyone can check it offline with either verifier: the record hashes to the recorded digest, its kind is the recorded kind, the entry is in a tree whose head we signed, and, for a signed leaf, your own signature holds. # validate a record against its pack, then fingerprint it node records.mjs validate statement.json node records.mjs digest statement.json # prints salt_hex and record_digest; keep both # after recording: bundle it with the proof, and check it the way a supervisor would node records.mjs bundle statement.json --salt $SALT --proof proof.json > bundle.json node records.mjs check bundle.json --key signing-key.json python3 riskrouter_verify.py bundle.json --key signing-key.json records.mjs ships with the conformance suite , beside the packs, and in the public verifier repository ; the Python verifier is in the kit . The Python client's record_structured() does steps 2 and 3 for you. What the log proves What a bundle shows, and what it cannot It shows That this exact record, with these field values, existed no later than the head's time and the Bitcoin block its anchor is in, and has not been changed since. With a signed leaf, that you asserted it. A correction is a new record naming the old one in supersedes , and the old one stays: what was there before a correction can always be seen. It does not show That the record is true or complete, that an obligation applied to you, or that you met it. Whether a regime applies, what it requires of you, and how long to keep records are for you and your supervisor. Where the log adds most Where a rule asks that records cannot be altered or that logs are kept: Delegated Regulation (EU) 2017/565, Article 72(1), and the AI Act's Articles 12, 19 and 26(6). A database row can be edited by whoever administers it; a fingerprint in an anchored tree cannot be changed without the change showing. EU AI Act DORA GDPR Article 22 Insurance Distribution Directive MiFID II NIS2 and data breaches EU AI Act pack ai-act version 1 High-risk AI systems: logs, decisions and human oversight What a provider or deployer of a high-risk AI system records so that its logs, the decisions taken on the system's output, and the human oversight exercised over it can be shown later to be exactly what existed at the time. The law Regulation (EU) 2024/1689 (Artificial Intelligence Act) (CELEX 32024R1689) Kinds ai.log-segment log segment sealed ai.decision decision taken on the system's output ai.oversight human oversight exercised The file /packs/ai-act.json , with an example record for every kind How long to keep it Articles 19(1) and 26(6) set a minimum of six months for the logs they cover, unless other law provides otherwise; this pack does not decide your period. Whether your system is high-risk, and from when these obligations apply to it, is yours to establish from the Regulation. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Regulation (EU) 2024/1689, Article 12(1) High-risk AI systems must technically allow for the automatic recording of events (logs) over the lifetime of the system. ai.log-segment : system_ref, segment_start, segment_end, event_count, log_digest, previous_segment_record_id Regulation (EU) 2024/1689, Article 12(2) Logging must enable recording of events relevant for identifying situations that may result in the system presenting a risk or in a substantial modification, for post-market monitoring (Article 72), and for monitoring the system's operation (Article 26(5)). ai.log-segment : system_version ai.decision : system_ref, system_version, input_digest, output_digest, decided_at Regulation (EU) 2024/1689, Article 14(4)(d) The people overseeing the system must be able to decide, in any particular situation, not to use it or to disregard, override or reverse its output. ai.decision : human_involved ai.oversight : system_ref, decision_record_id, overseer_ref, action, reason, acted_at Regulation (EU) 2024/1689, Article 19(1) Providers keep the logs their high-risk AI systems generate automatically, to the extent the logs are under their control, for a period appropriate to the system's intended purpose and of at least six months, unless Union or national law, in particular on personal data, provides otherwise. ai.log-segment : role, log_digest, retain_until Regulation (EU) 2024/1689, Article 19(2) Providers that are financial institutions subject to internal-governance requirements under Union financial services law keep those logs as part of the documentation kept under that law. ai.log-segment : retain_until Regulation (EU) 2024/1689, Article 26(6) Deployers keep the logs the system generates automatically, to the extent the logs are under their control, for a period appropriate to the system's intended purpose and of at least six months, unless applicable law provides otherwise. ai.log-segment : role, log_digest, retain_until Regulation (EU) 2024/1689, Article 86(1) A person affected by a decision a deployer takes on the basis of output from a high-risk AI system listed in Annex III (other than point 2), with legal or similarly significant adverse effects, may obtain clear and meaningful explanations of the role of the AI system in the decision and of the main elements of the decision taken. ai.decision : system_ref, case_ref, output_summary, role_of_system, decision ai.log-segment Log segment sealed When: Each time a segment of the system's automatic log is closed: every hour, every day, or every file rotation. Field What to put in it Type Mapped to system_ref Your reference for the AI system. your reference Article 12(1) system_version The version of the system that produced the log. one line Article 12(2) role Whether you keep this log as the provider or as a deployer. one of provider , deployer Article 19(1) Article 26(6) segment_start Time of the first event in the segment, UTC. UTC time Article 12(1) segment_end Time of the last event in the segment, UTC. UTC time Article 12(1) event_count How many events the segment holds, so a shortened log is caught. whole number Article 12(1) log_digest SHA-256 of the segment file exactly as stored. SHA-256 Article 12(1) Article 19(1) Article 26(6) log_format (optional) The format of the segment, such as jsonl. one line previous_segment_record_id (optional) The record_id of the segment before this one, so a missing segment is caught. your reference Article 12(1) retain_until (optional) The date until which you have decided to keep this segment. date Article 19(1) Article 26(6) Article 19(2) ai.decision Decision taken on the system's output When: When a decision about a person or a case is taken on the basis of the system's output. Field What to put in it Type Mapped to system_ref Your reference for the AI system. your reference Article 12(2) Article 86(1) system_version The version of the system that produced the output. one line Article 12(2) case_ref Your reference for the case or the person concerned. Never a name. your reference Article 86(1) input_digest (optional) SHA-256 of the input exactly as the system received it. SHA-256 Article 12(2) output_digest (optional) SHA-256 of the output exactly as the system produced it. SHA-256 Article 12(2) output_summary What the system output, in words someone can check against the output. text Article 86(1) role_of_system The role the system's output played in the decision. text Article 86(1) decision The decision taken, and its main elements. text Article 86(1) human_involved Whether a person reviewed the output before the decision. true or false Article 14(4)(d) decided_at When the decision was taken, UTC. UTC time Article 12(2) ai.oversight Human oversight exercised When: When a person overseeing the system confirms, overrides, reverses or declines to use its output, or stops it. Field What to put in it Type Mapped to system_ref Your reference for the AI system. your reference Article 14(4)(d) decision_record_id (optional) The record_id of the ai.decision record concerned, if any. your reference Article 14(4)(d) overseer_ref Your reference for the person who acted. Never a name. your reference Article 14(4)(d) action What the person did with the output. one of confirmed , overridden , reversed , not-used , stopped Article 14(4)(d) reason Why. text Article 14(4)(d) acted_at When, UTC. UTC time Article 14(4)(d) The log itself never leaves you: only the digest of each segment is recorded. A segment produced later can then be shown to be the segment that existed when it was sealed, and event_count and previous_segment_record_id make a shortened or missing segment visible. DORA pack dora version 1 ICT incidents, incident reports and the register of information What a financial entity records so that its incident log, the reports it sent to its competent authority and its register of ICT third-party arrangements can be shown later to be exactly what existed at each date. The law Regulation (EU) 2022/2554 (Digital Operational Resilience Act) (CELEX 32022R2554) Kinds dora.incident incident recorded at a stage dora.incident-report report submitted to the competent authority dora.register-snapshot register of information at a date The file /packs/dora.json , with an example record for every kind How long to keep it This pack does not state how long to keep these records. Check the period with your competent authority. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Regulation (EU) 2022/2554, Article 17(1) Define, establish and implement an ICT-related incident management process to detect, manage and notify ICT-related incidents. dora.incident : stage, detected_at, stage_at Regulation (EU) 2022/2554, Article 17(2) Record all ICT-related incidents and significant cyber threats, with procedures for consistent monitoring, handling and follow-up so root causes are identified, documented and addressed. dora.incident : incident_ref, category, description, root_cause, actions Regulation (EU) 2022/2554, Article 18 Classify ICT-related incidents and determine their impact against the criteria the article sets. dora.incident : classification, services_affected Regulation (EU) 2022/2554, Article 19(4) For a major ICT-related incident, submit to the competent authority an initial notification, an intermediate report and a final report. dora.incident-report : incident_ref, report_type, authority, report_digest, submission_ref, submitted_at Regulation (EU) 2022/2554, Article 28(3) Maintain and update a register of information on all contractual arrangements for ICT services provided by ICT third-party service providers. dora.register-snapshot : as_of, register_digest, arrangements, purpose dora.incident Incident recorded at a stage When: At each stage of an ICT-related incident or significant cyber threat: detected, classified, resolved, closed. Field What to put in it Type Mapped to incident_ref Your reference for the incident. your reference Article 17(2) stage The stage this record captures. one of detected , classified , resolved , closed Article 17(1) category Whether it is an incident or a significant cyber threat. one of ict-related-incident , significant-cyber-threat Article 17(2) classification Your classification under Article 18 at this stage. one of major , not-major , not-yet-classified Article 18 services_affected (optional) Your references for the services affected. list of your reference Article 18 description What happened, as known at this stage. text Article 17(2) root_cause (optional) The root cause, once identified. text Article 17(2) actions (optional) What was done, and what will be done to prevent recurrence. text Article 17(2) detected_at When the incident was detected, UTC. UTC time Article 17(1) stage_at When this stage was reached, UTC. UTC time Article 17(1) dora.incident-report Report submitted to the competent authority When: When an initial notification, an intermediate report or a final report is submitted. Field What to put in it Type Mapped to incident_ref Your reference for the incident. your reference Article 19(4) report_type Which report. one of initial-notification , intermediate-report , final-report Article 19(4) authority The competent authority it went to. one line Article 19(4) report_digest SHA-256 of the report exactly as submitted. SHA-256 Article 19(4) submission_ref (optional) The authority's acknowledgement reference, if any. your reference Article 19(4) submitted_at When it was submitted, UTC. UTC time Article 19(4) dora.register-snapshot Register of information at a date When: Each time the register is updated, and when it is submitted. Field What to put in it Type Mapped to as_of The date the register describes. date Article 28(3) register_digest SHA-256 of the register file exactly as kept or submitted. SHA-256 Article 28(3) arrangements How many contractual arrangements it lists. whole number Article 28(3) file_format (optional) The format of the file, as your authority names it. one line purpose Whether this is an internal update or the version submitted. one of update , submission Article 28(3) The reports themselves go to your authority by its own channel; the log never sends anything to anyone. What the log adds is that the report you hold today can be shown to be the one you held on the day you submitted it. GDPR Article 22 pack gdpr-art22 version 1 Automated individual decisions: basis, information and human intervention What a controller records to show, for a decision based solely on automated processing, which exception it relied on, what the person was told, and what happened when they asked for a human to look again. The law Regulation (EU) 2016/679 (General Data Protection Regulation) (CELEX 32016R0679) Kinds gdpr.automated-decision automated decision taken gdpr.human-intervention human intervention requested and handled The file /packs/gdpr-art22.json , with an example record for every kind How long to keep it This pack does not state how long to keep these records. The records are yours and hold personal data under your control: keep them no longer than your purposes need, and they stay erasable because they never leave you. Only a salted digest is in the log, and without the record and its salt nobody, including us, can link it to anyone. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Regulation (EU) 2016/679, Article 5(2) The controller is responsible for, and must be able to demonstrate, compliance with the principles in Article 5(1). gdpr.automated-decision : basis_ref, outcome, decided_at gdpr.human-intervention : reasons Regulation (EU) 2016/679, Article 13(2)(f) and Article 14(2)(g) Inform the person of the existence of automated decision-making, including profiling, referred to in Article 22(1) and (4), and at least in those cases give meaningful information about the logic involved and the significance and envisaged consequences. gdpr.automated-decision : information_digest Regulation (EU) 2016/679, Article 22(1) A person has the right not to be subject to a decision based solely on automated processing, including profiling, which produces legal effects concerning them or similarly significantly affects them. gdpr.automated-decision : subject_ref, decision_ref, solely_automated, significant_effect Regulation (EU) 2016/679, Article 22(2) That does not apply where the decision is necessary for entering into or performing a contract, is authorised by Union or Member State law with suitable safeguards, or is based on the person's explicit consent. gdpr.automated-decision : exception, basis_ref Regulation (EU) 2016/679, Article 22(3) Where the contract or explicit-consent exception applies, the controller implements suitable measures, at least the right to obtain human intervention, to express one's point of view and to contest the decision. gdpr.automated-decision : safeguards_offered gdpr.human-intervention : subject_ref, decision_record_id, request, requested_at, reviewer_ref, result, reasons, concluded_at gdpr.automated-decision Automated decision taken When: When a decision falling within Article 22(1) is taken, or when you conclude a decision does not fall within it. Field What to put in it Type Mapped to subject_ref Your pseudonymous reference for the person. Never a name, an email or a national number. your reference Article 22(1) decision_ref Your reference for the decision. your reference Article 22(1) solely_automated Whether the decision was based solely on automated processing. true or false Article 22(1) significant_effect Whether it produces legal effects concerning the person or similarly significantly affects them. true or false Article 22(1) exception The Article 22(2) exception relied on, or that the decision is outside Article 22(1). one of contract , union-or-member-state-law , explicit-consent , not-within-article-22 Article 22(2) basis_ref (optional) Your reference for the contract, the legal provision or the consent record relied on. your reference Article 22(2) Article 5(2) information_digest (optional) SHA-256 of the notice given to the person about the automated decision, as given. SHA-256 Article 13(2)(f) and Article 14(2)(g) safeguards_offered The safeguards offered with the decision. list of human-intervention , express-point-of-view , contest-decision Article 22(3) outcome The decision, in a short phrase. one line Article 5(2) decided_at When the decision was taken, UTC. UTC time Article 5(2) gdpr.human-intervention Human intervention requested and handled When: When the person asks for human intervention, expresses a point of view or contests the decision, and again when that request is concluded. Field What to put in it Type Mapped to subject_ref Your pseudonymous reference for the person. Never a name. your reference Article 22(3) decision_record_id The record_id of the gdpr.automated-decision record concerned. your reference Article 22(3) request What the person asked for. one of human-intervention , express-point-of-view , contest-decision Article 22(3) requested_at When the request arrived, UTC. UTC time Article 22(3) reviewer_ref (optional) Your reference for the person who reviewed. Never a name. your reference Article 22(3) result Where the request stands, or how it ended. one of pending , upheld , changed , reversed Article 22(3) reasons (optional) Why the decision was upheld, changed or reversed. text Article 22(3) Article 5(2) concluded_at (optional) When the review concluded, UTC. UTC time Article 22(3) Recording that a decision was outside Article 22(1) is as useful as recording one inside it: it shows the question was asked at the time. Insurance Distribution Directive pack idd version 1 Insurance distribution: demands and needs, advice and product information What an insurance distributor records to show, later, what the customer needed, what was proposed and why, and what information the customer received before the contract. The law Directive (EU) 2016/97 (Insurance Distribution Directive) (CELEX 32016L0097) Kinds idd.demands-needs demands and needs idd.recommendation personalised recommendation idd.ipid-provided product information document handed over The file /packs/idd.json , with an example record for every kind How long to keep it This pack does not state how long to keep these records. Check the period that applies to you with your supervisor or your professional federation. In Belgium the directive is transposed by the Act of 4 April 2014 on insurance, and the FSMA supervises its conduct rules. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Directive (EU) 2016/97, Article 20(1), first subparagraph Before a contract is concluded, specify the customer's demands and needs on the basis of information obtained from the customer, and give objective information about the product in a comprehensible form. idd.demands-needs : customer_ref, product_class, information_obtained, demands_and_needs, specified_at Directive (EU) 2016/97, Article 20(1), second subparagraph Any contract proposed must be consistent with the customer's insurance demands and needs. idd.demands-needs : proposed_product_ref, consistency_note Directive (EU) 2016/97, Article 20(1), third subparagraph Where advice is given before a specific contract is concluded, give the customer a personalised recommendation explaining why a particular product would best meet their demands and needs. idd.demands-needs : advice_given idd.recommendation : customer_ref, demands_needs_record_id, recommended_product_ref, reasons, document_digest, given_at Directive (EU) 2016/97, Article 20, paragraphs 4 to 9 For non-life products, give the product information by way of the standardised insurance product information document (IPID). idd.ipid-provided : customer_ref, product_ref, ipid_version, ipid_digest, provided_at Directive (EU) 2016/97, Article 23 How information reaches the customer: on paper, or on another durable medium or a website where the conditions for that are met. idd.recommendation : document_digest, medium idd.ipid-provided : medium idd.demands-needs Demands and needs When: Once the customer's demands and needs are specified, before any contract is concluded. Field What to put in it Type Mapped to customer_ref Your own reference for the customer. Never a name. your reference Article 20(1), first subparagraph product_class The class of cover discussed, in your own terms, such as motor or home. one line Article 20(1), first subparagraph information_obtained What the customer told you, and how you obtained it. text Article 20(1), first subparagraph demands_and_needs The demands and needs you specified from that information. text Article 20(1), first subparagraph proposed_product_ref (optional) Your reference for the product you proposed, if any. your reference Article 20(1), second subparagraph consistency_note (optional) Why the proposed contract is consistent with those demands and needs. text Article 20(1), second subparagraph advice_given Whether you gave advice. If true, an idd.recommendation record follows. true or false Article 20(1), third subparagraph adviser_ref (optional) Your reference for the person who handled the customer. Never a name. your reference specified_at When the demands and needs were specified, UTC. UTC time Article 20(1), first subparagraph idd.recommendation Personalised recommendation When: When advice is given, once the recommendation is handed to the customer. Field What to put in it Type Mapped to customer_ref Your own reference for the customer. Never a name. your reference Article 20(1), third subparagraph demands_needs_record_id The record_id of the idd.demands-needs record this recommendation answers. your reference Article 20(1), third subparagraph recommended_product_ref Your reference for the product recommended. your reference Article 20(1), third subparagraph reasons Why this product would best meet the customer's demands and needs. text Article 20(1), third subparagraph document_digest (optional) SHA-256 of the recommendation document exactly as the customer received it. SHA-256 Article 20(1), third subparagraph Article 23 medium How the recommendation reached the customer. one of paper , durable-medium , website Article 23 given_at When the recommendation was given, UTC. UTC time Article 20(1), third subparagraph idd.ipid-provided Product information document handed over When: For a non-life product, when the IPID is given to the customer. Field What to put in it Type Mapped to customer_ref Your own reference for the customer. Never a name. your reference Article 20, paragraphs 4 to 9 product_ref Your reference for the product. your reference Article 20, paragraphs 4 to 9 ipid_version The version of the IPID, as the manufacturer labels it. one line Article 20, paragraphs 4 to 9 ipid_digest SHA-256 of the IPID file exactly as handed over. SHA-256 Article 20, paragraphs 4 to 9 medium How the IPID reached the customer. one of paper , durable-medium , website Article 23 provided_at When it was provided, UTC. UTC time Article 20, paragraphs 4 to 9 The Worker's own quote ledger (v1) can record what was proposed and priced; this pack covers what stays with you. MiFID II pack mifid2 version 1 Investment advice: the suitability assessment and the statement on suitability What an investment firm records to show what it knew about the client when it advised, what it advised, and that the statement on suitability existed, unaltered, before the transaction. The law Directive 2014/65/EU (MiFID II) (CELEX 32014L0065) Commission Delegated Regulation (EU) 2017/565 (CELEX 32017R0565) Kinds mifid.suitability suitability assessment mifid.suitability-statement statement on suitability The file /packs/mifid2.json , with an example record for every kind How long to keep it This pack does not state how long to keep these records. Check the period that applies to you with your competent authority; in Belgium the FSMA supervises these conduct rules. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Directive 2014/65/EU, Article 25(2) When providing investment advice or portfolio management, obtain the information needed on the client's knowledge and experience in the relevant investment field, financial situation including ability to bear losses, and investment objectives including risk tolerance, so as to recommend what is suitable. mifid.suitability : client_ref, service, knowledge_and_experience, financial_situation, ability_to_bear_losses, investment_objectives, risk_tolerance, assessed_at Directive 2014/65/EU, Article 25(6) When providing investment advice, before the transaction is made, give the retail client a statement on suitability in a durable medium, specifying the advice given and how it meets the client's preferences, objectives and other characteristics. mifid.suitability-statement : client_ref, assessment_record_id, instruments, advice, how_it_meets_the_client, statement_digest, provided_at Commission Delegated Regulation (EU) 2017/565, Article 54 How the suitability assessment is carried out, and what the suitability report must contain. mifid.suitability : knowledge_and_experience, financial_situation, investment_objectives, other_preferences, method_ref mifid.suitability-statement : how_it_meets_the_client Commission Delegated Regulation (EU) 2017/565, Article 72(1) Records are kept so the competent authority can access them readily and reconstitute each key stage, so any corrections or amendments and the contents before them can be easily ascertained, and so they cannot otherwise be manipulated or altered. mifid.suitability : assessed_at mifid.suitability-statement : assessment_record_id, transaction_ref mifid.suitability Suitability assessment When: When the information for the suitability assessment has been obtained and assessed, before advice is given. Field What to put in it Type Mapped to client_ref Your own reference for the client. Never a name. your reference Article 25(2) service The service the assessment is for. one of investment-advice , portfolio-management Article 25(2) knowledge_and_experience The client's knowledge and experience in the investment field relevant to the product or service. text Article 25(2) Article 54 financial_situation The client's financial situation, as obtained. text Article 25(2) Article 54 ability_to_bear_losses Your assessment of the client's ability to bear losses. one line Article 25(2) investment_objectives The client's investment objectives. text Article 25(2) Article 54 risk_tolerance The client's risk tolerance, in your own scale. one line Article 25(2) other_preferences (optional) Any other preference your assessment method records. text Article 54 method_ref (optional) Your reference for the questionnaire or method version used. your reference Article 54 adviser_ref (optional) Your reference for the adviser. Never a name. your reference assessed_at When the assessment was completed, UTC. UTC time Article 25(2) Article 72(1) mifid.suitability-statement Statement on suitability When: When the statement on suitability is given to the retail client, before the transaction is made. Field What to put in it Type Mapped to client_ref Your own reference for the client. Never a name. your reference Article 25(6) assessment_record_id The record_id of the mifid.suitability record the advice rests on. your reference Article 25(6) Article 72(1) instruments The instruments advised, by identifier such as ISIN. list of your reference Article 25(6) advice The advice given. text Article 25(6) how_it_meets_the_client How the advice meets the client's preferences, objectives and other characteristics. text Article 25(6) Article 54 statement_digest SHA-256 of the statement exactly as the client received it. SHA-256 Article 25(6) provided_at When the statement was provided, UTC. The log's own time bounds it from above. UTC time Article 25(6) transaction_ref (optional) Your reference for the transaction that followed, if any. your reference Article 72(1) A correction is a new record whose supersedes field names the record it corrects; the earlier record stays in the log. That is how Article 72(1)'s requirement that corrections and earlier contents can be ascertained shows up in the evidence. NIS2 and data breaches pack nis2 version 1 Security incidents and logs: NIS2 incident handling and reporting, and personal-data breaches What an organisation records so that, after a security incident, it can show which logs existed before the incident, what it knew and when, what it did, and what it reported to whom. The law Directive (EU) 2022/2555 (NIS2 Directive) (CELEX 32022L2555) Regulation (EU) 2016/679 (General Data Protection Regulation) (CELEX 32016R0679) Kinds security.log-segment log segment sealed security.incident incident recorded at a stage security.notification report or notification sent The file /packs/nis2.json , with an example record for every kind How long to keep it Neither NIS2 nor GDPR Article 33(5) states how long to keep these records, and this pack does not decide it for you. Check the period with your competent authority or supervisory authority. What each article asks, in our words, and where a record answers it Article What it asks (our summary; the linked text is the law) Recorded in Directive (EU) 2022/2555, Article 21(1) Essential and important entities take appropriate and proportionate technical, operational and organisational measures to manage the risks posed to the security of the network and information systems they use. security.log-segment : source_ref, log_digest Directive (EU) 2022/2555, Article 21(2)(b) Those measures include incident handling. security.log-segment : source_ref, segment_index, segment_start, segment_end, line_count, log_digest, previous_segment_record_id security.incident : incident_ref, stage, description, actions, stage_at, log_segment_record_ids Directive (EU) 2022/2555, Article 23(1) Notify the CSIRT or, where applicable, the competent authority without undue delay of any significant incident, and where appropriate the recipients of the services concerned. security.incident : significant security.notification : recipient Directive (EU) 2022/2555, Article 23(4) For a significant incident: an early warning within 24 hours of becoming aware of it, an incident notification within 72 hours, an intermediate report on request, and a final report within one month of the incident notification. security.incident : aware_at security.notification : incident_ref, stage, aware_at, submitted_at, report_digest Regulation (EU) 2016/679, Article 33(1) Notify a personal data breach to the supervisory authority without undue delay and, where feasible, within 72 hours of becoming aware of it, unless it is unlikely to result in a risk to people's rights and freedoms; a later notification gives the reasons for the delay. security.incident : aware_at security.notification : incident_ref, stage, recipient, aware_at, submitted_at, report_digest, delay_reason Regulation (EU) 2016/679, Article 33(5) Document every personal data breach, comprising the facts relating to it, its effects and the remedial action taken, so the supervisory authority can verify compliance with the article. security.log-segment : segment_start, segment_end, log_digest security.incident : incident_ref, personal_data_breach, description, effects, actions, log_segment_record_ids security.notification : report_digest Regulation (EU) 2016/679, Article 34(1) When a breach is likely to result in a high risk to people's rights and freedoms, communicate it to the people concerned without undue delay. security.notification : stage, recipient security.log-segment Log segment sealed When: Each time a segment of a system's log is closed: after a number of lines, a number of seconds, or a file rotation. The logseal tool in the recorder kit does this for you. Field What to put in it Type Mapped to source_ref Your reference for the system or log source, such as fw-edge-1 or auth-server. your reference Article 21(1) Article 21(2)(b) segment_index The position of this segment in its source's sequence, from 0, so a missing segment is caught. whole number Article 21(2)(b) segment_start When the segment was opened, UTC. UTC time Article 21(2)(b) Article 33(5) segment_end When the segment was closed, UTC. UTC time Article 21(2)(b) Article 33(5) line_count How many lines the segment holds, so a shortened segment is caught. whole number Article 21(2)(b) log_digest SHA-256 of the segment exactly as archived. SHA-256 Article 21(1) Article 21(2)(b) Article 33(5) log_format (optional) The format of the lines, such as syslog, journald-json or cloudtrail-json. one line previous_segment_record_id (optional) The record_id of the segment before this one, so a removed segment is caught. your reference Article 21(2)(b) security.incident Incident recorded at a stage When: At each stage of a security incident: detected, assessed, contained, resolved, closed. Field What to put in it Type Mapped to incident_ref Your reference for the incident. your reference Article 21(2)(b) Article 33(5) stage The stage this record captures. one of detected , assessed , contained , resolved , closed Article 21(2)(b) significant Whether you consider it a significant incident under NIS2 at this stage. one of yes , no , not-yet-assessed Article 23(1) personal_data_breach Whether it is a personal data breach, as known at this stage. one of yes , no , not-yet-known Article 33(5) description The facts, as known at this stage. Refer to people by your own references, never by name. text Article 21(2)(b) Article 33(5) effects (optional) Its effects, as known at this stage. text Article 33(5) actions (optional) The remedial action taken, and what will be done to prevent recurrence. text Article 21(2)(b) Article 33(5) aware_at When you became aware of the incident, UTC: the reporting deadlines run from here. UTC time Article 23(4) Article 33(1) stage_at When this stage was reached, UTC. UTC time Article 21(2)(b) log_segment_record_ids (optional) The record_ids of the sealed log segments that cover the incident. list of your reference Article 21(2)(b) Article 33(5) security.notification Report or notification sent When: Each time something is sent about an incident: an early warning, a notification, an intermediate or final report, a breach notification, a communication to the people concerned. Field What to put in it Type Mapped to incident_ref Your reference for the incident. your reference Article 23(4) Article 33(1) stage What was sent. one of early-warning , incident-notification , intermediate-report , final-report , breach-notification , data-subject-communication Article 23(4) Article 33(1) Article 34(1) recipient To whom it was sent. one of csirt , competent-authority , supervisory-authority , service-recipients , data-subjects Article 23(1) Article 33(1) Article 34(1) aware_at When you became aware of the incident, UTC, as stated in what was sent. UTC time Article 23(4) Article 33(1) submitted_at When it was sent, UTC. UTC time Article 23(4) Article 33(1) report_digest SHA-256 of what was sent, exactly as sent, so the copy you keep can be shown to be the one you sent. SHA-256 Article 23(4) Article 33(1) Article 33(5) delay_reason (optional) Why it was sent after the deadline, if it was. text Article 33(1) The logs never leave you: the logseal tool in the recorder kit archives each segment on your own storage and sends only the digest of its record. A segment sealed before an intruder controlled the machine that writes it cannot be changed afterwards without it showing; what that machine writes once it is controlled can be forged at the source, and no seal changes that. Financial entities under DORA report ICT incidents under DORA, whose own pack covers them. Read this before using a pack What a pack is not A pack is a data format and a reading of the law, not legal advice, and using one does not make a firm meet any obligation. The summaries of articles are ours, written for orientation; the text on EUR-Lex, linked from each pack, is the law, and national rules and supervisory guidance add to it. We do not decide whether a regime applies to you. We never see your records, handle your customers, or report to your supervisor on your behalf. The log accepts any kind, packed or not: a pack is a convention you may adopt, never a condition of using the API. The packs, like the specification , are published so that another implementation can read the same records without us. Something wrong in a summary or a mapping? Tell us , and the correction goes in the changelog . ## What EU law asks you to record, and prove · RiskRouter URL: https://riskrouter.eu/obligations Obligations what the law already asks for The law already asks for the record. It does not say how you will prove it. Six EU laws ask a regulated firm to do something, and later to show it did: specify a customer’s needs, explain a recommendation, keep an AI system’s logs, record an incident. Each lets you keep that record in your own systems. None says how you will show, years later, that the record you produce is the one that existed at the time. Every system that stores a record can also edit it, so on the day a record is disputed, that is the question that decides. This page sets out, for each law, what its articles ask, when the record gets tested, and what a record sealed in the evidence log adds. The summaries are ours and the linked EUR-Lex text is the law. It is orientation, not legal advice: whether an article applies to you, and from when, is yours to establish. Six laws, one question Law When the record is tested What a sealed record adds Insurance Distribution Directive A complaint to the insurer or the ombudsman, a claim refused because the cover did not match the need, a supervisor's inspection. The demands-and-needs note and the recommendation are sealed when they are written, so the note you produce is shown to be the one that existed before the contract, not one written after the complaint. MiFID II A client disputes the advice after a loss; the supervisor asks you to reconstitute each stage of it. A correction is a new sealed record that names the record it corrects, and the earlier one stays, so what was changed and what stood before can be ascertained, as Article 72(1) describes. EU AI Act A person affected by a decision asks for an explanation; a market surveillance authority asks for the logs. Each log segment is sealed as it is written, with its event count and the segment before it, so a shortened, edited or missing segment shows. GDPR Article 22 A person contests an automated decision; the data protection authority asks you to demonstrate compliance. The basis of the decision, and any human review of it, are shown to have been recorded at the time, while the record, which holds personal data, stays with you and erasable. NIS2 and data breaches A CSIRT or regulator asks what happened and when you knew; a cyber insurer assesses a claim; a customer or a court disputes your account of a breach. Logs sealed segment by segment before the incident cannot be rewritten afterwards without it showing, and each report you sent is shown to be the one you hold, sent when you say. DORA Your authority reviews a major incident; an auditor compares the report you hold with the report you sent. The incident record and each report are sealed when they are made, so the report you hold today is shown to be the one you held on the day you submitted it. Insurance Distribution Directive Who it concerns Insurance distributors: brokers, agents, and insurers selling directly. Whether it applies to you, and from when, is yours to establish from the text. When it is tested A complaint to the insurer or the ombudsman, a claim refused because the cover did not match the need, a supervisor's inspection. What a sealed record adds The demands-and-needs note and the recommendation are sealed when they are written, so the note you produce is shown to be the one that existed before the contract, not one written after the complaint. How long to keep it This pack does not state how long to keep these records. Check the period that applies to you with your supervisor or your professional federation. In Belgium the directive is transposed by the Act of 4 April 2014 on insurance, and the FSMA supervises its conduct rules. What to record The Insurance Distribution Directive pack : idd.demands-needs , idd.recommendation , idd.ipid-provided Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Directive (EU) 2016/97, Article 20(1), first subparagraph Before a contract is concluded, specify the customer's demands and needs on the basis of information obtained from the customer, and give objective information about the product in a comprehensible form. Directive (EU) 2016/97, Article 20(1), second subparagraph Any contract proposed must be consistent with the customer's insurance demands and needs. Directive (EU) 2016/97, Article 20(1), third subparagraph Where advice is given before a specific contract is concluded, give the customer a personalised recommendation explaining why a particular product would best meet their demands and needs. Directive (EU) 2016/97, Article 20, paragraphs 4 to 9 For non-life products, give the product information by way of the standardised insurance product information document (IPID). Directive (EU) 2016/97, Article 23 How information reaches the customer: on paper, or on another durable medium or a website where the conditions for that are met. MiFID II Who it concerns Investment firms that give investment advice or manage portfolios. Whether it applies to you, and from when, is yours to establish from the text. When it is tested A client disputes the advice after a loss; the supervisor asks you to reconstitute each stage of it. What a sealed record adds A correction is a new sealed record that names the record it corrects, and the earlier one stays, so what was changed and what stood before can be ascertained, as Article 72(1) describes. How long to keep it This pack does not state how long to keep these records. Check the period that applies to you with your competent authority; in Belgium the FSMA supervises these conduct rules. What to record The MiFID II pack : mifid.suitability , mifid.suitability-statement Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Directive 2014/65/EU, Article 25(2) When providing investment advice or portfolio management, obtain the information needed on the client's knowledge and experience in the relevant investment field, financial situation including ability to bear losses, and investment objectives including risk tolerance, so as to recommend what is suitable. Directive 2014/65/EU, Article 25(6) When providing investment advice, before the transaction is made, give the retail client a statement on suitability in a durable medium, specifying the advice given and how it meets the client's preferences, objectives and other characteristics. Commission Delegated Regulation (EU) 2017/565, Article 54 How the suitability assessment is carried out, and what the suitability report must contain. Commission Delegated Regulation (EU) 2017/565, Article 72(1) Records are kept so the competent authority can access them readily and reconstitute each key stage, so any corrections or amendments and the contents before them can be easily ascertained, and so they cannot otherwise be manipulated or altered. EU AI Act Who it concerns Providers and deployers of high-risk AI systems, which include risk assessment and pricing for natural persons in life and health insurance, and assessing the creditworthiness of natural persons (Annex III, point 5). Whether it applies to you, and from when, is yours to establish from the text. When it is tested A person affected by a decision asks for an explanation; a market surveillance authority asks for the logs. What a sealed record adds Each log segment is sealed as it is written, with its event count and the segment before it, so a shortened, edited or missing segment shows. How long to keep it Articles 19(1) and 26(6) set a minimum of six months for the logs they cover, unless other law provides otherwise; this pack does not decide your period. Whether your system is high-risk, and from when these obligations apply to it, is yours to establish from the Regulation. What to record The EU AI Act pack : ai.log-segment , ai.decision , ai.oversight Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Regulation (EU) 2024/1689, Article 12(1) High-risk AI systems must technically allow for the automatic recording of events (logs) over the lifetime of the system. Regulation (EU) 2024/1689, Article 12(2) Logging must enable recording of events relevant for identifying situations that may result in the system presenting a risk or in a substantial modification, for post-market monitoring (Article 72), and for monitoring the system's operation (Article 26(5)). Regulation (EU) 2024/1689, Article 14(4)(d) The people overseeing the system must be able to decide, in any particular situation, not to use it or to disregard, override or reverse its output. Regulation (EU) 2024/1689, Article 19(1) Providers keep the logs their high-risk AI systems generate automatically, to the extent the logs are under their control, for a period appropriate to the system's intended purpose and of at least six months, unless Union or national law, in particular on personal data, provides otherwise. Regulation (EU) 2024/1689, Article 19(2) Providers that are financial institutions subject to internal-governance requirements under Union financial services law keep those logs as part of the documentation kept under that law. Regulation (EU) 2024/1689, Article 26(6) Deployers keep the logs the system generates automatically, to the extent the logs are under their control, for a period appropriate to the system's intended purpose and of at least six months, unless applicable law provides otherwise. Regulation (EU) 2024/1689, Article 86(1) A person affected by a decision a deployer takes on the basis of output from a high-risk AI system listed in Annex III (other than point 2), with legal or similarly significant adverse effects, may obtain clear and meaningful explanations of the role of the AI system in the decision and of the main elements of the decision taken. GDPR Article 22 Who it concerns Any controller whose decisions about people are made, wholly or partly, by automated processing. Whether it applies to you, and from when, is yours to establish from the text. When it is tested A person contests an automated decision; the data protection authority asks you to demonstrate compliance. What a sealed record adds The basis of the decision, and any human review of it, are shown to have been recorded at the time, while the record, which holds personal data, stays with you and erasable. How long to keep it This pack does not state how long to keep these records. The records are yours and hold personal data under your control: keep them no longer than your purposes need, and they stay erasable because they never leave you. Only a salted digest is in the log, and without the record and its salt nobody, including us, can link it to anyone. What to record The GDPR Article 22 pack : gdpr.automated-decision , gdpr.human-intervention Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Regulation (EU) 2016/679, Article 5(2) The controller is responsible for, and must be able to demonstrate, compliance with the principles in Article 5(1). Regulation (EU) 2016/679, Article 13(2)(f) and Article 14(2)(g) Inform the person of the existence of automated decision-making, including profiling, referred to in Article 22(1) and (4), and at least in those cases give meaningful information about the logic involved and the significance and envisaged consequences. Regulation (EU) 2016/679, Article 22(1) A person has the right not to be subject to a decision based solely on automated processing, including profiling, which produces legal effects concerning them or similarly significantly affects them. Regulation (EU) 2016/679, Article 22(2) That does not apply where the decision is necessary for entering into or performing a contract, is authorised by Union or Member State law with suitable safeguards, or is based on the person's explicit consent. Regulation (EU) 2016/679, Article 22(3) Where the contract or explicit-consent exception applies, the controller implements suitable measures, at least the right to obtain human intervention, to express one's point of view and to contest the decision. NIS2 and data breaches Who it concerns Essential and important entities under NIS2: medium-sized and large organisations in the sectors of its Annexes I and II, and some others whatever their size (Article 2); for personal-data breaches, every controller under the GDPR. Financial entities report ICT incidents under DORA instead. Whether it applies to you, and from when, is yours to establish from the text. When it is tested A CSIRT or regulator asks what happened and when you knew; a cyber insurer assesses a claim; a customer or a court disputes your account of a breach. What a sealed record adds Logs sealed segment by segment before the incident cannot be rewritten afterwards without it showing, and each report you sent is shown to be the one you hold, sent when you say. How long to keep it Neither NIS2 nor GDPR Article 33(5) states how long to keep these records, and this pack does not decide it for you. Check the period with your competent authority or supervisory authority. What to record The NIS2 and data breaches pack : security.log-segment , security.incident , security.notification Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Directive (EU) 2022/2555, Article 21(1) Essential and important entities take appropriate and proportionate technical, operational and organisational measures to manage the risks posed to the security of the network and information systems they use. Directive (EU) 2022/2555, Article 21(2)(b) Those measures include incident handling. Directive (EU) 2022/2555, Article 23(1) Notify the CSIRT or, where applicable, the competent authority without undue delay of any significant incident, and where appropriate the recipients of the services concerned. Directive (EU) 2022/2555, Article 23(4) For a significant incident: an early warning within 24 hours of becoming aware of it, an incident notification within 72 hours, an intermediate report on request, and a final report within one month of the incident notification. Regulation (EU) 2016/679, Article 33(1) Notify a personal data breach to the supervisory authority without undue delay and, where feasible, within 72 hours of becoming aware of it, unless it is unlikely to result in a risk to people's rights and freedoms; a later notification gives the reasons for the delay. Regulation (EU) 2016/679, Article 33(5) Document every personal data breach, comprising the facts relating to it, its effects and the remedial action taken, so the supervisory authority can verify compliance with the article. Regulation (EU) 2016/679, Article 34(1) When a breach is likely to result in a high risk to people's rights and freedoms, communicate it to the people concerned without undue delay. DORA Who it concerns Financial entities within DORA's scope, including insurers and insurance intermediaries, other than intermediaries that are micro, small or medium-sized enterprises (Article 2(3)). Whether it applies to you, and from when, is yours to establish from the text. When it is tested Your authority reviews a major incident; an auditor compares the report you hold with the report you sent. What a sealed record adds The incident record and each report are sealed when they are made, so the report you hold today is shown to be the one you held on the day you submitted it. How long to keep it This pack does not state how long to keep these records. Check the period with your competent authority. What to record The DORA pack : dora.incident , dora.incident-report , dora.register-snapshot Article (links to the text on EUR-Lex) What it asks (our summary; the linked text is the law) Regulation (EU) 2022/2554, Article 17(1) Define, establish and implement an ICT-related incident management process to detect, manage and notify ICT-related incidents. Regulation (EU) 2022/2554, Article 17(2) Record all ICT-related incidents and significant cyber threats, with procedures for consistent monitoring, handling and follow-up so root causes are identified, documented and addressed. Regulation (EU) 2022/2554, Article 18 Classify ICT-related incidents and determine their impact against the criteria the article sets. Regulation (EU) 2022/2554, Article 19(4) For a major ICT-related incident, submit to the competent authority an initial notification, an intermediate report and a final report. Regulation (EU) 2022/2554, Article 28(3) Maintain and update a register of information on all contractual arrangements for ICT services provided by ICT third-party service providers. What no law requires, and what the log does not do No law names a product None of these laws requires RiskRouter or any other product. You can meet every duty on this page without us. What we offer is a way to show you met it that does not depend on anyone’s word, including ours. It proves when, not whether A sealed record is shown to have existed, unchanged, no later than a signed and anchored head. The log does not know what the record says, so it cannot make a record correct, complete or sufficient, and recording something does not make anyone compliant. The record stays with you Only a salted fingerprint of each record is sent. The record, and any personal data in it, never reach us, so it stays yours to keep and to erase. Data protection It outlives us Every proof checks offline with the open-source verifier , against keys and anchors that are published. Continuity To start, take a sandbox key and record a fingerprint in a few minutes, or read what to record, rule by rule . ## DORA Article 30 contract terms, clause by clause · RiskRouter URL: https://riskrouter.eu/dora For procurement, risk and DORA review DORA Article 30, clause by clause A financial entity may rely on an ICT provider only under a written contract that contains the provisions Regulation (EU) 2022/2554 (DORA) , Article 30, lists. Below is each of those provisions, the clause we offer for it, and what is in place today. Where something is not in place, it says so. These are proposed terms. RiskRouter has no legal entity registered yet, so no contract can be signed today ( facts for your register of information ). When one can, these are the terms we will put in it, in one written document you can keep. The summaries of the Regulation are ours and the linked text is the law. This is not legal advice: your counsel should check the clauses against your own policy, and whether the function we support is critical or important is your assessment. Article 30(2): in every contract (a) The services, and subcontracting Requires A clear and complete description of the functions and services, saying whether subcontracting is permitted and on what conditions. We offer The service is described in the order form: the evidence log ( /api/v2 ), the quote ledger and pricing engine ( /api/v1 ), with the API reference as the technical description at the date of signature. Subcontracting is permitted only to the providers listed on the data protection page . We give you at least 30 days’ written notice before adding or replacing one, and you may terminate without charge if you object. In place today The description and the list of subprocessors are published. (b) Where services are provided and data is kept Requires The regions or countries where the services are provided and data is processed and stored, and advance notice of any change. We offer Stored in the EU: the database is in Frankfurt, Germany. Requests are handled at the Cloudflare location nearest the caller, which may be outside the EEA, and nothing is stored there. An encrypted daily backup is kept on GitHub for 90 days, outside the EU. At least 30 days’ written notice before any of these changes. In place today As stated, and published on Trust . (c) Availability, authenticity, integrity and confidentiality of data Requires Provisions on the availability, authenticity, integrity and confidentiality of data, including personal data. We offer Integrity is the product: entries are append-only in the database itself, hash-chained, under signed heads with public timestamps and a Bitcoin anchor, and you can check all of it without us. Your records never reach us: only salted fingerprints are sent. Only the SHA-256 of an API key is stored. A data processing agreement under GDPR Article 28 is attached where any personal data is processed on your behalf. In place today Built, tested in CI, and described in the specification and on Security . (d) Access to your data, and its return, whatever happens to us Requires Access, recovery and return of your data in an easily accessible format if the provider becomes insolvent, is resolved or stops, or the contract ends. We offer You can export everything you recorded at any time, in an open JSON format, without a ticket or a fee, and it verifies without us. We give at least 90 days’ written notice before discontinuing the service, and the export stays available throughout that period and any transition period under (3)(f). In place today The export, the open format and the public verifier. What you keep (e) Service levels Requires Service level descriptions, including their updates and revisions. We offer The service levels agreed for your contract, in the order form. Every change to the API and to the rating matrix is listed in the changelog , with at least 90 days’ written notice before we remove or change anything you rely on; live availability is on the status page . In place today No service level is offered during the validation build. It is agreed in writing per pilot. (f) Help when an incident touches the service Requires Assistance when an ICT incident related to the service occurs, at no additional cost or at a cost fixed in advance. We offer Assistance at no additional cost: the facts, logs and timeline we hold about the incident, and our help in establishing what it affected. In place today Incident notes are kept in the repository, and the ledger’s own history is independently checkable. (g) Cooperation with your authorities Requires Full cooperation with your competent and resolution authorities, and the people they appoint. We offer Full cooperation, without charge. In place today A commitment; nothing is needed to begin it. (h) Ending the contract Requires Termination rights and minimum notice periods that meet your authorities’ expectations, including the grounds in Article 28(7). We offer You may end the contract at any time, for any reason, with no notice period and no termination fee, as well as on every ground in Article 28(7). We may end it for convenience only with at least 90 days’ written notice, and never without the transition period under (3)(f) if you ask for it. In place today Leaving needs nothing from us but revoking your key. The steps to leave (i) Security awareness and resilience training Requires The conditions on which the provider takes part in your ICT security awareness programmes and digital operational resilience training (Article 13(6)). We offer We take part when you ask, at no charge. In place today A commitment. Article 30(3): where the service supports a critical or important function Whether it does is your assessment. If it does, the contract also needs the following, and the first is not something we can offer yet. Tell us before a pilot starts, so it is settled in writing rather than discovered later. (a) Measurable service levels Requires Full service level descriptions with precise quantitative and qualitative performance targets, so you can monitor the service and act when a target is missed. In place today Not offered. During the validation build we publish no availability target and give no service credit. A contract for a critical or important function would need them agreed first. (b) Notice of anything that affects the service Requires Notice periods and reporting obligations, including notice of any development that might materially affect the provider’s ability to provide the service. We offer Notice of any incident affecting the service without undue delay, and in any case within 24 hours of our becoming aware of it; and prompt written notice of any development that might materially affect our ability to provide it. (c) Contingency plans and security measures Requires Business contingency plans that are implemented and tested, and appropriate ICT security measures, tools and policies. In place today A daily restore drill, run automatically, that restores the production ledger into a fresh database and checks every entry; the engine can also run in your own account. Restore drill Running it yourself . The database plan keeps no backups of its own, no penetration test has been done, and no certification is held. Security (d) Threat-led penetration testing Requires Participation and full cooperation in your threat-led penetration testing (Articles 26 and 27). We offer Full participation and cooperation, on terms agreed in advance so the test does not disturb other customers. (e) Monitoring, access, inspection and audit Requires Unrestricted rights of access, inspection and audit for you, a third party you appoint, and your competent authority, with the right to take copies; alternative assurance levels where other customers’ rights are affected; cooperation during inspections; and details of their scope and frequency. We offer Those rights, on reasonable notice to us, and without notice where your competent authority requires it. Much of the evidence is already public and checkable without asking us: the log, its heads, the anchors and the software bill of materials . (f) Exit, with a transition period Requires Exit strategies, including a mandatory adequate transition period during which the provider keeps providing the service, so you can move to another provider or in-house. We offer On any termination, including ours, the service continues at your request for a transition period of up to six months, on the same terms. In place today The documented exit plan. Continuity and exit plan Facts for your register of information Discuss a pilot’s terms ## Sealed security logs: evidence after a breach · RiskRouter URL: https://riskrouter.eu/security-logs Security logs evidence for after an incident After a breach, the logs are the first thing an intruder rewrites. When something goes wrong, everyone turns to the logs: your own investigators, the authority you report to, a cyber insurer assessing the claim, a customer who asks what happened to their data. An intruder knows this, and editing or deleting the lines that show what they did is often the first thing they do. A log you can still edit is your word about what happened, not evidence of it. logseal seals your logs as they are written, segment by segment, into the evidence log. Each segment is archived on your own storage, and only a salted fingerprint of its record reaches us. Later, anyone can check offline that every sealed segment is exactly what was written, and that none has gone missing. What it proves No sealed segment was changed Each segment’s SHA-256 is inside a record sent to the log as soon as the segment closes and the log can be reached. Change one line afterwards and the segment no longer gives the sealed digest. None went missing Segments are numbered and each record names the one before it, so a removed, inserted or renumbered segment shows. logseal verify lists exactly which. When, independently of you The log’s signed heads are timestamped by two independent authorities (not qualified under eIDAS) and anchored in Bitcoin, so a segment is shown to have existed no later than a time nobody can move. What you reported, and when Seal each early warning, notification and report as you send it, and the copy you hold is shown to be the one you sent, when you say you sent it. Checkable without us The open-source verifiers check a record’s proof offline, and logseal verify checks the archive against your own journal. Nobody has to trust you, or us. What it cannot do It does not detect anything It is not an intrusion detection system or a SIEM. It keeps the evidence of an incident; it does not spot one. It cannot say who did it It does not identify an attacker or decide who was responsible. Investigators reach those conclusions from the logs; the seal makes sure those logs can be trusted. It cannot protect lines written after a takeover Once an intruder controls the machine that writes a log, what that machine writes from then on can be forged at the source. What the seal protects is everything sealed before. Run logseal on a log collector the watched systems cannot reach, not on each of them. It does not make anyone compliant NIS2 and the GDPR ask for incident handling, reports and documentation. Sealing shows when a record existed; whether the record is enough is yours to judge. What each article asks How it runs logseal is part of the drop-in recorder kit (Apache-2.0, no dependencies). It reads lines on standard input, so it takes anything that can print a log: journalctl , tail -F , a syslog relay, an export of cloud audit logs. journalctl -f -o short-iso | riskrouter-logseal --source auth-server --archive /var/lib/logseal \ --lines 1000 --seconds 60 --format syslog riskrouter-logseal verify --archive /var/lib/logseal --journal evidence-journal.jsonl # auth-server: 412 of 412 sealed segments intact, 412 recorded in the log A segment Closes after a number of lines or seconds, whichever comes first. It is written once to the archive, synced, and never overwritten; only then is its record sealed. The record A security.log-segment record of the NIS2 and data-breach pack : the source, the segment’s number, its time span, its line count and its SHA-256. The record and its salt stay in your journal; the log lines never leave your storage. A restart Carries on the same numbered chain from the last archived segment. An outage Records wait in your journal and are sent when the log answers again; nothing is lost, and nothing is marked recorded before the log has answered. The same pack records each stage of an incident, and each report or notification you send. Download: logseal.mjs , with the recorder it uses, from the recorder kit . Recording needs a key; a sandbox key is free, with no form and no contract. Who it is for Organisations under NIS2, which must handle incidents and report significant ones within 24 hours, 72 hours and a month; every controller under the GDPR, which must document each personal-data breach; and anyone who will one day have to show a cyber insurer, an authority or a court what their logs said before an incident. Financial entities report ICT incidents under DORA, whose pack covers them. ## AI agents and assistants: connect over MCP · RiskRouter URL: https://riskrouter.eu/ai For AI agents, assistants and the people who build them An AI decision you cannot show later is an AI decision you cannot defend. When an AI system advises, scores or acts, someone will one day ask what it did and why: a customer, a supervisor, a court. RiskRouter gives AI systems the same evidence log it gives brokers: each record stays with you, only its salted fingerprint is sealed, and anyone can check it offline. This page is everything an AI agent, an assistant or its builder needs, in one place. Connect an assistant in one step The evidence log is an MCP server at https://api.riskrouter.eu/mcp (Streamable HTTP). Reading needs no key. Recording needs your key in an Authorization header; a sandbox key is free, with no form and no contract. Claude Code claude mcp add --transport http riskrouter https://api.riskrouter.eu/mcp \ --header "Authorization: Bearer " Cursor, and any client configured in JSON { "mcpServers": { "riskrouter": { "url": "https://api.riskrouter.eu/mcp", "headers": { "Authorization": "Bearer " } } } } Claude, and other clients that add a server by its address Add a custom connector with the address above. If the client cannot send an Authorization header, it can still read the log and fetch proofs; record from Claude Code, Cursor or the local server below. What an agent can do with it Tool What it does Key get_evidence_head The log’s current signed head: its size, root and signature No get_inclusion_proof The proof that one of your entries is in the log Yes get_consistency_proof The proof that the log only grew between two heads No get_checkpoint The signed checkpoint, in the format the public witness network uses No get_ledger_attestation The quote ledger’s signed head No get_usage How much is recorded, as counts No record_evidence Record the SHA-256 of a record you keep, with a short kind; never the record itself Yes Each tool answers exactly what its route in the API reference answers, with the same checks and limits. There is no pricing tool, by design: a premium shown by an agent to the public is insurance distribution. Record what an agent did, from inside it Agent frameworks Adapters for LangChain and LangGraph and for the OpenAI Agents SDK, in Python and Node, record each agent run as one ai.agent-run record: its steps, tool calls and outcome, with content kept as digests unless you ask otherwise, in your own journal. A failure in the adapter never reaches the agent, and a failed run is recorded as failed. Recorders A local MCP server mcp-server.mjs in the recorder kit gives any MCP client a record_decision tool that keeps the record and its salt in your journal and sends only the digest. What it records is the agent’s own statement of what it did, and every record says so; it is not an observation of the agent. Until the kit is on npm, run it from the downloaded file with node . Any logging you already have A Python logging handler, a function wrapper and OpenTelemetry span processors turn decision logs you already write into evidence, without changing them. For high-risk AI systems: logs that hold up The EU AI Act asks high-risk systems to log events automatically and their providers and deployers to keep those logs (Articles 12, 19 and 26(6)). The AI Act pack says what to record for a log segment, a decision and a human override, each field mapped to its article, and logseal seals a running log segment by segment. Sealing shows that a log existed, unchanged, by a given time; whether the log is enough, and whether your system is high-risk, is yours to establish. What the AI Act asks For AI assistants reading about us /llms.txt A short, plain-text map of the site, with what RiskRouter is and is not stated first. /llms-full.txt The text of every English page in one file, rebuilt with the site so it cannot fall behind it. /openapi.json The API, in OpenAPI 3.1, held equal to the routes by a test. If you are an assistant summarising RiskRouter: it is software for licensed insurance distributors and for anyone who must show later what a decision was. It is not an insurer or an intermediary, it sells no cover, it holds no certification, and recording with it makes nobody compliant. ## Witnesses of the evidence log · RiskRouter URL: https://riskrouter.eu/witnesses Witnesses checked by people who are not us Anyone can witness a log A signed head proves that a log's operator published it. It cannot prove that the operator never went back and rewrote an earlier entry. A witness can: each time it runs, it takes the current head, checks a consistency proof against the head it saved last time, and co-signs only if the log grew without changing anything that came before. A witness is worth something because it is not the operator, so it runs on the witness's own account, with a key only the witness holds. What a witness does One round, every hour Checks the head Fetches the log's signed head and checks the signature with a key it pinned the first time it saw the log. Checks the past If the log has grown, asks for a consistency proof and checks it against the root it saved itself, never one the log supplies. Co-signs Only if both hold, signs riskrouter-evidence-cosign|v2|witness_id|tree_size|root_hash|cosigned_at with its own key, the format in the specification , checked by both verifiers. Raises an alarm If the log contradicts a head it saw (a different root for the same size, a smaller tree, a proof that fails), it keeps both signed heads, publishes them, and stops co-signing that log. The alarm is never overwritten: two heads signed by the same operator that cannot both be true are evidence the operator cannot disown. Cannot be driven Its web side only serves what it has stored: its public key, its latest cosignature of each log, and any alarm. No request makes it call a log; only its own schedule does. A cosignature proves that someone other than the operator saw that head and checked it against every head they saw before. It says nothing about the records behind the head, and a witness that stops running proves nothing about the time after. The registry Every log, and everyone who witnesses one A witness can follow the registry and witness every log it lists. The registry is a convenience, not a source of trust: a witness pins each log's keys on first sight, and if the registry later drops or changes a pinned key, the witness raises an alarm instead of taking the new one. A registry may not point a witness at a private address. Logs Log Operator API Head-signing keys riskrouter RiskRouter https://api.riskrouter.eu dd4b4b394c95586a ( published ) Witnesses No witnesses yet. Nobody outside RiskRouter witnesses a log in this registry today, and until someone does, a rewritten history would be caught only by a holder who kept an older head. This page lists a witness only once they publish their key somewhere under their own control. The public witness network Our log also speaks the C2SP formats the public witness network uses: a checkpoint at /tlog/evidence-v2/checkpoint and hash tiles beside it ( specification ). Its key is api.riskrouter.eu/tlog/evidence-v2+05e20636+AZsv9x6CMqcAlnY+GmAtkFthrxjtaGKnVpQEH9ZAkL7J . No witness of that network cosigns our log yet: we have not been accepted into its list. Rendered from registry/logs.json , witnesses/ and anchors/ when this page was built. The same data, as JSON: /registry.json . Become a witness Three ways to run one, each on your own account The witness is published in the public verifier repository , in witness/ , beside the verifiers. Every way starts by making a key; the private half stays with you. node witness/node.mjs init --out ./my-witness --name "Your organisation" # ./my-witness/private-key.b64 secret: goes into a secret store, never into a repository # ./my-witness/public-key.json publish it on your own site, and send it to us to be listed A Cloudflare Worker Copy witness/wrangler.toml.example , create a KV namespace, add the key as a secret and deploy. An hourly Cron Trigger witnesses every log in the registry; the Worker serves its cosignatures at /cosignatures//latest.json . The free plan is enough. A fork on GitHub Fork the verifier repository, copy witness/github-workflow.yml to .github/workflows/ , add the key as the secret WITNESS_PRIVATE_KEY . Every hour it witnesses and commits its cosignatures to witness-state/ in your fork, where anyone can read them. If it ever raises an alarm, the run fails after committing the evidence. Your own server node witness/node.mjs run --state ./state --every 3600 --port 8080 : the same witness, storing its state in a directory and serving it read-only. Node 20 or later, no dependencies. To be listed, send us your public-key.json , the https address where you publish the same key, and, if you serve your cosignatures, the address of your witness. We add a file to witnesses/ ; from then on a daily job collects your latest cosignature of our log, keeps it only if it verifies with your key and ours and is consistent with our current head, and counts it here. We list nobody who has not published their key themselves. Cross-witnessing Every instance can witness every other An organisation that runs the engine itself can switch on the witness in the same stack: docker compose --profile witness up -d . It follows the registry, so it witnesses our log and every other listed log, and it can also witness its own. A self-hosted log whose operator publishes its keys can be listed too, and is then witnessed by everyone who follows the registry. Each new participant makes every log in the registry harder to rewrite unnoticed, including ours. There is no fee, no contract and no account with us in any of this. A witness owes us nothing and we cannot switch one off. ## Questions and answers about RiskRouter URL: https://riskrouter.eu/faq Questions and answers Questions and answers about RiskRouter The questions people ask before they write to us, answered in a sentence or two. Each answer links to the page that holds the detail, so nothing here has to be taken on our word. If your question is not here, ask it . What RiskRouter is What is RiskRouter? Evidence infrastructure for licensed insurance distributors and the software they use. It keeps an append-only, independently verifiable record of what was advised and quoted, so a broker can later prove exactly what existed at the time. It also has an optional server-side pricing engine, which today prices a simulated rate grid. For software vendors · For brokers Is RiskRouter an insurer or an insurance intermediary? Neither. It is not an insurer and, in our own analysis, not an insurance intermediary: it gives no advice, proposes and concludes no contracts, never deals with the policyholder, and is paid a flat software fee. It is not registered with the FSMA. What the FSMA said, and what it did not · Regulatory position Is RiskRouter required by law? No. No law requires RiskRouter or any other product. The law requires the records themselves: IDD, MiFID II, the AI Act, GDPR Article 22 and DORA each ask a firm to do something and later to show it did. What RiskRouter adds is a way to show a record was never changed that does not rest on anyone’s word. What the law asks you to record Does RiskRouter sell insurance? No. Nothing on this site is an offer of insurance and no cover is in force. The prices the demo shows come from a simulated rate grid, and no contract can be concluded through it. Regulatory position Is it in production? It is a validation build. The API, the evidence log, the proofs and the verifiers are live and can be used with a sandbox key today; pricing is deterministic mock rules, and there is no customer yet. Status · Usage in numbers Data and privacy What data does RiskRouter receive? For the evidence log, only a salted SHA-256 digest of your record and a short tag such as ai.decision . The record itself, the customer’s name and the salt stay with you. Pricing a quote involves no personal data at all. Data protection · How a digest is made Can an entry be deleted? No. The log is append-only on purpose, which is what makes it evidence. That is why it holds only digests: the record stays in your own systems, where you can erase it when the law requires, and a salted digest on its own says nothing about anyone. Specification Where is data stored? In Frankfurt, inside the EU. An encrypted daily backup of the ledger is kept on GitHub for 90 days, and it never includes contact-form enquiries. Data protection · Trust Is RiskRouter certified (ISO 27001, SOC 2)? No. We hold no certification, and our providers’ certifications do not make us certified. What we offer instead is evidence you can check yourself. Security questionnaire Proof and continuity How do I check a record without trusting RiskRouter? With the open-source verifier, offline: it checks that your record gives the recorded digest, that the entry is in the log, and that the log’s signature holds. Public timestamps and a Bitcoin anchor fix when each head existed. Verify a record · Open-source verifier What happens if RiskRouter disappears? The evidence outlives us. Every proof checks offline with the public verifier, the log’s keys and anchors are published, and you can export what you recorded at any time. The engine can also run in your own account. Continuity Who else checks the log? The log publishes signed checkpoints in the format the public witness network cosigns, and anyone can run a witness of it. No outside witness cosigns it yet, and the page counts them from the published files. Witnesses Are the timestamps qualified under eIDAS? No. Every signed head gets RFC 3161 tokens from two independent time-stamping authorities and a Bitcoin anchor, but those authorities are not qualified, and every page and verifier says so. Specification Getting started How do I start? Take a sandbox key yourself, with no form and no contract, and run the integration kit against it. Integrate How much does it cost? There is no commercial price yet: this is a validation build, and the sandbox is free. The rating matrix the engine prices is public. API reference · Changelog Which languages and systems does it support? Any system that can make an HTTPS request. The integration kit is ready in PHP, C#/.NET, Python and Java using only their standard libraries, and drop-in recorders for Python and Node turn existing decision logs into evidence. No SDK is required. Integrate Can AI agents use it? Yes. Any MCP client can connect to https://api.riskrouter.eu/mcp to read the log and, with a key, record digests. Adapters for LangChain, LangGraph and the OpenAI Agents SDK record each agent run as one entry. There is no pricing tool for agents. Connect an AI agent Can we run it ourselves? Yes: the same engine runs in your own cloud account or on your own servers, against your own database, and calls nothing of ours. Running it needs the source and a licence agreed in writing. Continuity Is it open source? The verifier and the drop-in recorders are open source (the recorders under Apache-2.0), and the specification is public. The engine’s source is not licensed. Specification · Recorders