How to check this record
This page is not a green tick to trust. It sets out the exact method behind every hash shown on this site, and the values this run currently publishes, so the check can be done independently of this site.
The hash chain
Every recorded change is one line in an append-only log: a provider added, a provider removed or a page that changed. Each line carries event_hash, the SHA-256 of that event’s own fields (sorted keys, no inserted whitespace, the event_hash field itself excluded from what is hashed), and prev_event_hash, which must equal the event_hash of the line immediately before it. The very first line in a log points to 64 zero characters rather than to another event, because there is no event before it.
Editing, reordering or deleting any past line breaks this chain from that point forward, because every later line still claims the hash of what used to be there. A correction is never made by changing a line; it is a new line, dated when it was made.
The start of the current chain
The earliest event this record holds: the one line whose prev_event_hash is 64 zeros rather than another event’s hash.
- Recorded
- Event type
- baseline
- Source
- fr_pa_list
- Previous event hash
- 000000000000…(genesis)
- Event hash
- b9d182d18351…
Checking it without this site
Three checks, each independent of anything this site says about itself:
- The snapshot. An event written from a reading of an official page or file carries the SHA-256 of the exact bytes the publisher served. Refetch that page or file yourself and hash it; a match confirms this record captured exactly what the publisher had, byte for byte. This is the one check that depends on the publisher, and it holds only while the publisher still serves those bytes: once the file is replaced, a refetched copy no longer matches, and the mismatch says only that the file has changed. Where the portable archive carries the file, hash that copy instead. Which sources withhold their file, and what this record holds in its place, is set out under what is not served.
- The chain. The recording engine that produces this log is run with
python -m engine verify-chain, which walks every line, recomputes eachevent_hashand checks it againstprev_event_hashon the line after it, and reports the first line that fails. The same two-step algorithm above can be reimplemented in any language from the files this site serves, set out in the next section:chain_index.jsonlists every event in order by hash alone, and the bodies the log has published are inchanges.jsonand, for the complete log, in2026.json. To look a hash up, find the entry inchain_index.jsonwhoseevent_hashmatches: itsnis its place in the chain, the entry atn− 1 must be the hash its body names asprev_event_hash, andpublishedsays whether a body is published or held back. The log the engine writes,data/changelog.jsonl, is not served here; a reader holding the portable archive has it as well as these files, and the archive’s own checker walks it and uses it in the checks of each issued extract, as set out under what this proves. - The timestamp. See what dates a run: the digest of a run’s events, or on a day that recorded none its observation seal, is anchored independently of this site or its operator.
The published files, and where to fetch them
The chain check, and the checks of the published files against one another, can be run on files this site serves, as they were when this page was built. They are copied, byte for byte, from the export directory the build read; no second copy is kept, so what is served cannot drift from what was published. They are the files of the run dated .
chain_index.json3.8 KBEvery event in the chain by hash alone, in order, each marked published or withheld with the reason. This is the file to look a hash up in.changes.json19.3 KBThe change feed, newest first, capped from the old end. Not the whole log: the year logs hold every published event.run_summary.json37.5 KBThe run these files come from: its date, the timestamp digest, the counts and the latency figures set out on the method page.withdrawals.json3 bytesEach record that left an official list: the day, and the evidence for it (the digests of the last snapshot with it and the first without it, the event hash, the run digest).entities.json177.8 KBEach company, with every accreditation it holds (start day, end day, basis and the authority’s quoted sentence) and, kept apart, any statement the company itself has sent.providers.json71.3 KBOne record for each company on each official list: the list it appears on, whether it is still on it, and the first and last day this record saw it.countries.json79.9 KBEach country and the sources behind it: who publishes the list, its address, the terms of reuse, the authority’s own sentence about what the list means, and the mandate page.changes/index.jsonand2026.json19.4 KBThe complete change log, one file for each year: every published event, uncapped. The index lists the years and how many events each holds.history/index.jsonand 155 record files388.1 KBOne file for each record, holding the record and every event published about it. The company page links its records’ files.- The contract the files above are written to: every field and every value it may take.
These paths are fixed. They are the file names the export contract gives, under /exports/, and they will not move: a script that fetches one today will fetch the same path later. A path is added when the contract adds a file and is not taken back. The contract itself is served at /schema/exports.schema.json.
What is not served, and why
This site serves none of the publishers’ own files (the snapshots), whatever a publisher’s terms say, because whether a file may be republished is decided source by source and this site does not make that decision. The portable archive carries some of them. Each source declares a snapshot_policy in countries.json, and only the word public lets the engine keep the file where the archive can carry it, listed as included in snapshots/MANIFEST.sha256. Any other value, or none, keeps it out, and the manifest lists the file’s digest as absent.
A source declares private for one of two reasons, and either is enough.
- The terms. The publisher’s reuse terms are restrictive or silent, and a file whose terms do not allow it to be republished is withheld by default.
- What the file holds. It carries personal data that the record does not keep, such as a contact e-mail address on every row. The record drops that column when it reads the file, and a file that still holds it is not published, whatever its licence says.
So a withheld file does not show that the publisher’s terms are restrictive, and an open licence does not show that the file is published.
The register has read 2 sources in this set. 1 declares public, and the file of the other one is withheld:
If this table is wider than the space it has here, scroll it sideways to see every column.
| Source | Policy declared | Terms the register recorded | Last read |
|---|---|---|---|
| fr_pa_list France | private | Licence Ouverte / Etalab 2.0 (https://www.impots.gouv.fr/mentions-legales): 'les informations de ce site sont proposés sous licence ouverte Etalab 2.0'; site graphics excluded. |
countries.json records each source’s policy and the terms the register recorded for it. It does not record which of the two reasons applies, so this page does not say. Where the terms recorded allow the file to be republished, as an open licence does, they are not the reason, and the file is withheld for what it holds.
A further 61 sources are declared in countries.json and the register has not read them, so there is no file of their own to carry or to withhold. The page for each country lists the policy it declares.
What this record holds of a withheld file is its SHA-256 digest, on each event and each withdrawal row that cites one. A reader can check it only against a copy of the file, and the publisher’s own copy is the one most readers can reach, so the check holds while the publisher serves those bytes and no longer.
For a list, the engine also records parsed_sha256: the SHA-256 of the records it built from the file, names included and nothing the record drops. Since the engine began to record it, it has been on each baseline event, which ties the names to the count the baseline states, and in the observation seal of a day that recorded no event, which names the digest of what each source the run read yielded. It is a second claim about the same file and not a replacement for the first. providers.json publishes a reduced form of each record, so the digest cannot be recomputed from the published files, and only a reader who holds the publisher’s file can reproduce it.
The engine’s own log (data/changelog.jsonl), the timestamp proof files and the seals (run digests and observation seals) are in the portable archive, not here. The build checks the output for any of these, or for any path it does not recognise, and stops rather than publish it.
What dates a run
A seal is a short text file the engine writes into data/digests/, named from the run’s instant, and submits to public timestamp calendars using the OpenTimestamps standard. The calendars anchor it into the Bitcoin blockchain, which gives a proof that these exact bytes existed no later than a given time, checkable by anyone through the OpenTimestamps method, independently of this site. The proof (.ots) and the state of the stamp (.status) are files beside the seal. What a seal says depends on what the run did, and a run is one of three kinds. A day, here, is the UTC day of the run’s instant.
- A run that wrote events. The SHA-256 hashes of the events it wrote are concatenated and hashed again into one run digest. The seal names that digest, the first and last of those events, and the hash of
chain_index.jsonas published.run_summary.jsonrepeats the digest and the state of its stamp in astampblock, and the panel below shows them. - A run that read a source and wrote no event. There are no event hashes to digest, so such a run has no run digest and publishes no
stampblock. It writes an observation seal instead, whose first line iskind=observation. That seal names the run’s instant, the sources it read and the hash ofchain_index.jsonas published and, since the engine began to record it, the digest of what each source yielded. It is stamped in the same way, so a run that looked and found nothing to record is dated by its own proof. The seal and its proof are in the portable archive. The published files carry neither, and say nothing of whether the stamp completed. A quiet day from before the engine wrote observation seals has none, and the published files do not say which days those are. - A run that read no source. Every source was skipped. It writes no event and no observation seal, because a seal saying the register looked on a day it did not would be false, so no seal says the register looked on that day.
- Latest run
- Run digest
- 2280b65fcda2…
- Timestamp
stampedSubmitted to public timestamp calendars; the Bitcoin attestation is not complete yet.
A stamp has two stages. When a seal is submitted the calendars return a pending attestation, which is the state stamped. The Bitcoin attestation follows once the transaction that carries it confirms, which can take hours, and a weekly upgrade pass collects it for every seal whose state is stamped and changes the state to upgraded. That pass skips a seal in any other state. A seal whose stamp failed (stamp_failed), or that was made with no timestamp client (pending_no_ots), has no pending attestation to collect. The pass skips it and the engine does not stamp the same bytes a second time, so every event it names stays in the chain and only the independent proof of when it existed is missing. A day with no seal has nothing for the pass to collect.
What this proves, and what it does not
The checks above compare files with each other and with the stamp they carry. What they can establish depends on which files the reader holds, so this section answers for two readers separately. One holds the seven flat published files. The other holds the portable archive, which carries those same files and also the whole changelog, data/changelog.jsonl. They do not get the same answer to every question, and neither is told more than it can be: a record that says what it cannot show is worth more than one that implies it shows everything.
Two readers, two answers
Each check ends in one of three words: it passes, it fails because the files contradict each other or the chain, or it is unverified, meaning the files in the reader’s hands do not establish the row either way. Unverified is not a pass. A report can contain unverified rows without any check having failed.
Three columns. The third, the answer for the holder of the portable archive, comes last. If this table is wider than the space it has here, scroll it sideways to read it.
| Question | Holder of the seven flat files | Holder of the portable archive |
|---|---|---|
| The day a withdrawal row states, against the event it cites | Settled where the set holds the cited event and its links run to it. Where the cap dropped the entry and no link corroborates it, unverified: not established, and not reported as damage. | The check follows the pointer to data/changelog.jsonl and reads the event there. It passes where the chain agrees with the row and fails where the chain contradicts it. |
| The day a record joined the list | Three flat files state it, and two disagreeing is damage. A day later than a confirmed addition the reader holds fails. A day moved earlier in all three is unverified. | The record’s own events in the changelog state it, withheld readings included. A day the chain contradicts fails. Settled for every record whose addition the chain carries. |
| A record already listed when its source was first read | Compared with a count. The baseline states how many records it counted. If the set puts more records than that opening on that day, the row fails. The same number, or fewer, is unverified: a count cannot tell one record from another, and a reader holding less of the list is not holding damage. | Settled by the file the baseline read, where the archive carries it. The record’s name found in it passes; missing from a file that names the rest of that day’s records, it fails. Where the archive does not carry the file, or the names in it cannot be found, the flat-files answer stands. |
| Which company a record belongs to, and which authority published it | The files that name them are compared and fail outright where they differ. Not contradicted if every file is changed together. | The same comparison, and the record’s own events too, for the authority and the country: a record cannot change either and stay the same record. The company’s name and identifier are not read off events. |
| The authority’s word, and the sentence it quoted | The files that state the word are compared and fail where they differ; a sentence that denies an approval beside the word accredited fails. The word and the sentence are also compared with the declarations in force over the record’s own period in the events the capped feed holds, and fail where they differ. Where the feed holds no declaration over that period the answer is unverified. | The same comparison, over the whole changelog, which holds the events the capped feed does not: a record unverified from the feed can pass here. Still unverified where the changelog records no declaration over the period. What the authority wrote is settled on its own page, not by either reader. |
| Where the chain ends, and when anything was written | Not settled by these files: whoever publishes the set writes the index and the stamp in one pass, and nothing in the set is dated against anything else. | More securely, through the timestamp proof it carries, which is taken over bytes naming the index as published. Only once the proof is checked with ots verify; until then unverified. |
The difference can be seen on one row. Take a set whose feed carries only some of the bodies, and move the day on a withdrawal row in the flat files while leaving the chain honest. A reader holding only the flat files has that row reported as unverified, and the report as a whole is not marked failed. A reader holding the archive has the check follow the pointer to data/changelog.jsonl, find the event the row cites, and fail the row. On the unaltered set neither reader is told anything is wrong: the archive reader’s row passes, and the flat-files reader’s stays unverified.
What the published files settle
For a reader holding the seven flat files, four things, from these files alone, without trusting this site or its operator. Each is a statement that files agree with one another or with the chain, which is less than a statement that the listing is right, and the bound of each is given with it.
- The order. Every entry in
chain_index.jsonnames the entry that must sit immediately before it, and that value,prev_event_hash, sits inside the bodyevent_hashwas computed over. An entry cannot be re-issued into a different position without breaking a hash that was fixed when it was written. Worked out fromchain_index.jsonandchanges.jsonwhen this page was built: the feed carries 13 bodies, and each names the entry the index puts immediately before it. A body that did not would have stopped the build. - No withdrawal is hidden by policy. A body can be withheld from the feed: a provisional reading is held back until a second run confirms it. But a withdrawal row is not published beside a policy that would have kept it from being written. When this page was built, each of the 0 rows in
withdrawals.jsonwas read againstchain_index.json, and the build stops if the index does not list the event the row cites or withholds it asprovisional,quarantineorowner_hold. In this set 0 rows cite a published event. The same build stops on a withheld entry that gives no reason or a reason outside the four the contract allows; this set has 10 withheld entries, each with one. That is the part of the check this site makes. The archive’s own reader makes a wider one, which opens the bodies and the year logs, and which you run on the archive rather than take from this page. - Which company a record belongs to, and which authority published it.
entities.jsonnames, for each accreditation, the company (its identifier and name) and the source it came from, and with the source the country, the address of the official list and its terms of reuse.providers.jsonandwithdrawals.jsonname the same four things for the same record, each written from one stored record in one pass. A check compares them and fails outright where they differ, naming both values and the file.The bound. This shows the files agree, not that the listing is right, so a change made in every file at once is not contradicted by them. A reader who also holds the record’s events has the authority and the country contradicted too, because both are inputs to the record’s identifier and a record cannot change either and stay the same record. The company’s name and identifier are not read off events, because a company can be renamed, or a record moved between companies, honestly, and an older event would then honestly say otherwise. - The authority’s word, against its own quoted sentence. Each accreditation carries a
basis: what the authority says inclusion on its list means, in its own word (see what basis means). The word is stated for the source incountries.json, for the record inproviders.json, for each withdrawal inwithdrawals.jsonand on the accreditation inentities.json. A check fails outright where any of them differs, and where the sentence quoted on an accreditation differs from the one quoted for its source. A second check fails where the word isaccreditedand the sentence quoted beside it denies an approval, using a closed list of denial phrases drawn from the sentences this record holds; it fires on that word only, because each of the other four carries its own limit and a denial sits honestly under any of them.The bound. These show that the published files agree with one another and that a sentence does not contradict its word. They do not show that the word is the one the authority used. The first item under “What they do not settle” says what the chain adds to that, and where it stops.
What they do not settle
For that same reader, these are open or only partly settled, and each is bounded rather than hidden. The next two headings say which of them a reader holding the archive can close.
- The word the authority used, and when it said it. The agreement above is between files a publisher writes. The chain carries the word a second time: the authority’s word and the sentence it quoted are written into the body of every event a list-publishing source writes, before the event is hashed. Of the 13 events in
changes.json, 13 carry the word and 13 carry the sentence.What is caught. Changing either inside an event changes that event’s hash and breaks the chain from that line on, so a word forged inside the chain is caught by the chain check above. The engine that writes these files also refuses to publish a word the chain does not support, and a reader’s check now makes the same comparison, as the next paragraph sets out.What a reader’s check compares. The check on an issued extract reads the events its reader holds and sets the word the extract prints, and the sentence it quotes, against the declarations those events record as in force over that accreditation’s own period. Where they differ it fails outright: two statements about what one government did to one named company, one of them inside a hashed event, cannot both be right. So a publisher who raised the word in all four files, or replaced the quoted sentence in both places that carry it, is contradicted by the events although every published file then agrees with every other. The comparison is over the accreditation’s own period and not against the chain’s latest declaration, because a word declared after a company left the list never applied to it. It rests on the chain checks above that establish those events, and not on itself alone.Where it reports unverified, not failed. The chain may record no declaration over that period, and then there is nothing to read the word against. Four honest shapes reach it: events written before the word was hashed keep the shape they had; a source that declares no recognised word is refused before it is fetched, so it writes none; the published feed is capped from the old end and may hold no event of that source at all; and a period that closed before the chain’s first declaration began was never governed by it. In that state nothing contradicts the word and nothing corroborates it, so a word changed in every file, where the chain holds nothing over the period, is contradicted by no check. The reader holding the archive has the whole changelog, which extends the comparison where the feed is capped.A sentence that is missing is not a contradiction. The sentence is compared only where the extract quotes one and the events carry one. An authority that withdrew its sentence part-way through a period honestly leaves one declaration that carries it and one that does not, so an extract quoting none is not accused. A sentence deleted from both published files is therefore reported as unverified, not failed, and where the events carry a sentence the set no longer publishes the report says that they do. The word is still compared.What is not settled. What the authority actually wrote. The events record the word this ledger read and declared, and agreeing with them is not the authority standing behind it. That is settled on the authority’s own page, which the source block of every extract names. An event carrying no word is silence, not a contradiction, and a page source says nothing about what its page means. - Where the chain ends. This page used to say the newest published entry’s hash matching
last_event_hashin the run’s stamp settled that. It does not, and saying so was a mistake now corrected:chain_index.jsonnames its own last entry, and the stamp inrun_summary.jsonnames the last event of the run it seals. But whoever publishes the set writes both files in the same pass, so their agreeing shows they were written together, not that no further line exists. An entry added after the newest body the feed carries would be named by no published link either. The portable archive settles this more securely than the published set ever did: its timestamp proof is taken over bytes that name the index as published, so an index with a line added after that proof was taken is one no proof in the archive dates. - When any of it was written. Nothing in the published set carries a date these files can check against each other: agreeing with the stamp shows the files are consistent, not when they were produced. Only the OpenTimestamps proof carried in the portable archive answers that, and it has to be checked with
ots verifybefore it shows anything. What dates a run, above, explains the proof. - The position of an entry no published body links across. A link names the entry immediately before it, so it corroborates that one entry’s position and no other. Withholding a run of two or more entries in a row is legitimate, but only the last entry of that run is named by the body published after it; the entries inside the run are not. In this set’s
chain_index.json, that pins 4 of the 10 withheld entries, one per run:
| Run length | Runs |
|---|---|
| 1 | 3 |
| 7 | 1 |
This is a limit of what a windowed feed can show, not a defect in it: a feed that withheld nothing would be publishing provisional claims a second run has not yet confirmed. Where the exact position matters, the portable archive settles it. It carries the whole chain, not a window on it.
- A published entry the cap dropped, cited by a row, that no link in the set corroborates.
changes.jsonis capped from the old end, but an entry past the cap is still published, inchanges/<year>.jsonand in the record’s own history file. Where a row cites such an entry and this set holds no body that links across to it, the set cannot tell it from an entry inserted at that position, because the links reach a position only through the bodies above it. The check of a reader holding only the published files reports that row as unverified, not as damaged: calling it damaged would call every honest capped copy damaged too. That is true of that reader only; the archive reader’s check settles it, as set out below. A false day on such a row would have to lie inside [the day the record joined the list, the oldest day the feed reaches], and that window is empty whenever the cap’s edge falls before the record was listed. It is settled by evidence outside the seven flat files: the year log, the record’s own history file, ordata/changelog.jsonlin the portable archive, which carries the whole changelog. On any set this ledger itself writes, which carries the year log, this route fails. It is a limit of what seven flat files can show, not of the record. - The day a record joined the list. The day a period begins is stated three times in the flat files: the accreditation’s
from,first_seeninproviders.jsonandfirst_seeninwithdrawals.json, the same name in both. They are written from one stored value in one pass, so two of them disagreeing is damage and is reported as damage. A start day later than a confirmed addition of the same record that the reader holds is contradicted, because a capped feed can only be short of older entries. But a record’s first appearance is a provisional reading the feed withholds until a second run agrees, so on a set this ledger writes the first body a reader of the flat files holds for a record is one run late. A start day moved earlier in all three files is therefore not contradicted by them, and the check reports it as unverified, not as damaged. Whoever moved it had to move three files rather than one, and the day is settled exactly by the record’s own events indata/changelog.jsonl. - A record already on the list when its source was first read. Such a record has no addition of its own; the baseline reading is where its history starts. A baseline records how many records it counted, never their names, so this reader compares that count with the number of records that
providers.json(first_seen) orentities.json(from) date to the day the source was first read. A start day moved back to the day the source was first read puts one more record in that cohort, and a cohort larger than the count fails the row, because nothing a reader lacks can make a cohort larger than the list was. That is a count against a count: it catches a record added to a cohort and not a record swapped for another at the same count, and the same number reads as unverified. So does a cohort smaller than the count. A withheld cohort, or a copy trimmed to one country, holds less than the list did, and is reported as unverified and not as damage. The check reaches this only for a record with an event of its own dated after the day its period opens; a record whose whole history is the baseline holds none, and is unverified for both readers.
What a reader holding the portable archive settles in addition
The portable archive’s check does not stop at naming data/changelog.jsonl. It follows that pointer: it reads the changelog the archive carries and uses it in the check of each issued extract, where the flat-files reader’s report prints the pointer and leaves the lookup to the reader. Three things follow, each with its bound.
- The event a withdrawal row cites. The check finds the cited event in the changelog and compares the row with it. It passes where the chain agrees with the row and fails where the chain contradicts it, including a day moved in the flat files with the chain left honest, and and including an entry inserted at the position the row cites.
- The day a record joined the list, for every record whose addition the chain carries. The record’s own events in the changelog, the withheld provisional readings among them, state the day, and a start day the chain contradicts fails.
- The word and the sentence, for every record whose source the changelog declares a word for over the record’s period. The capped feed may hold no event of a source over an older record’s period, and the comparison is then unverified; the changelog holds every event, so the same comparison reaches the record. A word or a sentence the declarations contradict fails.
Two bounds apply to the first two, and the first of them to all three. First, the changelog is used only after the archive has walked it: if the chain check failed, or a line of the file cannot be read as an event, the changelog is set aside and each row is reported exactly as the flat-files reader would see it, because a body read out of a chain that does not walk could make a check pass. An archive built from the exported files alone carries no chain beyond the feed and gets the same flat-files answer. Second, a body found in the changelog still has to be reached by the set’s own links before a withdrawal row or a start day rests on it.
A fourth thing comes from the snapshots and not from the changelog. For a record already on the list when its source was first read, the archive reader looks for the record’s name in the file the baseline read, the one its snapshot_sha256 names, where the archive carries it. The name found there passes the row. The name missing from a file in which the names of the rest of that day’s records are found fails it, which settles a swap at the same count as well as an addition, because it reads the publisher’s own bytes and not a number. The search is for text, folded the way the ledger folds a company name to make its identifier, so a name could also be in a file for another reason.
What the archive reader still cannot settle
- What the authority wrote, and a period the changelog is silent on. The word and the sentence are compared with the changelog’s declarations, but the changelog records what this ledger read, and the authority’s own page is where what it wrote is settled. Where the changelog records no declaration over a record’s period, because the events predate the word being hashed or the source declares none, the answer is unverified for the archive reader as for anyone.
- A record already on the list, where the archive holds no snapshot to search.
snapshots/MANIFEST.sha256in the archive lists the file the baseline’s digest names, but the archive carries the file itself only where the source declarespublic. Without it, or where the names of the rest of that day’s records cannot be found in it, the row is unverified for the archive reader as for anyone, and a start day moved back to the day the source was first read is then tested only by the count above, which catches an addition and not a swap. A reader holding the publisher’s file can open it and look for the name. A baseline written since the engine began to recordparsed_sha256also carries the digest of the records it built, which that reader can reproduce (see what is not served). - When it was written. The archive carries the timestamp proofs, but a proof shows nothing until it has been checked with
ots verify, and a stamp that is still pending shows as unverified for the archive reader as for anyone.
This page is information taken from official published lists. It is not tax, legal or professional advice, and it does not replace checking the official source.