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.
Head hash
loading…
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 <hash from step 1>
# 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.
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.
Which public key is this checked against?
The one published in anchors/signing-key.json and in the
public verifier repository
(whose tools are Apache-2.0), 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.
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: …
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
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. Every day the evidence log moves, its newest signed head goes into Bitcoin as well: 13 heads are anchored so far, 13 already in a block, the earliest block 972 079. 34 heads carry an RFC 3161 time-stamp token from DigiCert timestamp service and Sectigo timestamp service, the latest issued at 2026-11-02 16:06:03 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.
Every head, day by day · 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 every day the log moves, so the window in which a time is only our word is at most about a day plus the time a block takes to confirm; the RFC 3161 tokens, taken every two hours, narrow it to about two hours, on the authority’s word. Every head, day by day: /age.