Verifying the ledger
How a customer, supplier, or auditor independently verifies an Open Tally ledger — the offline verifier, the public endpoints, and the exact workflow.
The point of the whole construction: a counterparty who does not trust the operator can still verify the books. This page describes verification against the linkex.ai instance; the workflow is the protocol's, so it generalizes to any instance.
The premise throughout: you do not need to believe anything linkex says, and you do not need an account. You need curl, the verifier, and — for the on-chain leg — any public Base block explorer.
The verifier
Verification runs with a zero-dependency, fully offline command-line verifier (linkex-verify; a single static binary of ~3.7 MB). Offline is a design requirement, not a convenience: a verifier that silently phones home could be lied to by whoever answers. The tool:
- verifies a single receipt bundle (
-bundle) or a whole period (-period), reporting PASS / FAIL / SKIPPED per check with the reason for every skip — a skipped check is never counted as passed; - prints, beside every result, what that check does not establish;
- supports strict mode (
-strict), pinned TSA trust roots (-tsa-roots), and machine-readable output (-json); - exits
0when all runnable checks pass,1on any failure, and3(with-strict) when a check could not run.
Open source
The verifier, the receipt specification, and the conformance vectors publish under the Open Tally
name — GitHub org opentallyprotocol, npm scope
@opentally. Counterparties of linkex.ai receive the
tooling directly today; watch the org for public releases. You can also
implement your own verifier — the specification is
written for exactly that, and it is the stronger position: you need not trust a binary the
operator hands you.
Step 0: pin the timestamp roots
Before anything else, fetch the timestamp authority's root certificate and check its fingerprint:
curl -sLo digicert-g4.pem https://cacerts.digicert.com/DigiCertTrustedRootG4.crt.pem
openssl x509 -in digicert-g4.pem -noout -fingerprint -sha256
# 55:2F:7B:DC:F1:A7:AF:9E:6C:E6:72:01:7F:4F:12:AB:F7:72:40:C7:8E:76:1A:C2:03:D1:D9:D2:0A:C8:99:88This step is not optional, and the reason is instructive. Without -tsa-roots, the verifier falls back to the host system's trust store — and the same valid DigiCert token verifies on Linux while being rejected on macOS. Same data, same program, different verdict depending on who is asking. When the conclusion must not depend on which machine asked the question, pinning the roots is a precondition, not an optimization. Every command below carries -tsa-roots digicert-g4.pem.
Three minutes: verify one specific charge
Disputes are usually about one call. This is the shortest path:
# 1) find the stream and sequence range you care about
curl -s "https://linkex.ai/api/receipt/commitments?page_size=50" | less
# 2) fetch the evidence bundle for that one receipt
curl -sf "https://linkex.ai/api/receipt/bundle?stream=ch:10&seq=2" -o receipt.json
# 3) verify — fully offline from here
./linkex-verify -bundle receipt.json -tsa-roots digicert-g4.pemThe bundle carries the receipt, its predecessor and successor (so chain continuity is checkable), the full key history, the covering period commitment, and the Merkle inclusion proof — everything needed with no further access to linkex systems.
Reading the result:
0 failedis the number to look at. Anyfailedmeans linkex's records disagree with their own cryptographic commitments — send the verifier output to linkex; that is an incident on their side.skippedis notpassed. The report explains each skip. In particular, a supplier-side bundle skips retail itemization by design — the seventh check explains why6 passed, 1 skippedis a full score for a supplier.
Ten minutes: verify a period
curl -sf "https://linkex.ai/api/receipt/period?stream=ch:10&sample=200" -o period.json
./linkex-verify -period period.json -tsa-roots digicert-g4.pemThis checks the commitment chain, key history, and timestamp tokens across the period, plus a sample of receipts with inclusion proofs. Two things to understand about that sample:
- It is drawn, not chosen. The seed is the period's last commitment hash — a value signed and time-fixed before the draw could be made — and the draw rule is published, so you can recompute any receipt's membership yourself. If linkex substituted a receipt that wasn't drawn, Merkle inclusion fails.
- PASS is not the conclusion — the printed miss probability is. The report states the probability that a sample this size would miss a single tampered receipt. Want a stronger bound? Raise
sample, or negotiate a scoped full-population disclosure. Proof bundles covers the semantics in full.
Don't trust the assembly either: build the bundle yourself
In the steps above, linkex assembled the bundle. If you don't want to trust the assembly, use only the two raw public endpoints and the published jq recipe:
curl -s "https://linkex.ai/api/receipt/commitments?stream=ch:10&page_size=200&include_tokens=1" > c.json
curl -s "https://linkex.ai/api/receipt/keys" > k.json
jq -n --slurpfile c c.json --slurpfile k k.json -f period-bundle.jq > mine.json
./linkex-verify -period mine.json -tsa-roots digicert-g4.pemThe recipe (period-bundle.jq) ships with the deliverables and is executed by linkex's own CI, so it cannot drift from the endpoints' response shapes. A self-assembled bundle covers the commitment layer only — it proves the ledger is complete, signed, and time-fixed, but not what the receipts say (that needs sampled receipts, above). The two paths are complementary; keep both.
Then check the chain
For any anchored window, follow the five-step walk from the transparency page down to a confirmed transaction on Base — the last two steps are against the public chain itself, with no linkex involvement at all.
The full workflow, in order
Pin the TSA roots
Fetch and fingerprint-check the timestamp authority's root certificate (step 0 above).
Fetch the public ledger
Pull the key history and the period commitments for the range you're auditing — or receive a pre-assembled bundle, or assemble your own.
Verify commitments and time fixing
Commitment signatures, the commitment chain, RFC 3161 tokens against your pinned roots, and — for anchored windows — the on-chain anchors on Base.
Verify your receipts
For the receipts disclosed to you: signatures against the published key history, sequence continuity, hash-chain continuity, Merkle inclusion — via sampling for scale, or receipt-by-receipt for a scoped range.
Recompute the money
Recompute every disclosed amount from the unit prices, price-book versions, and metering parameters recorded inside the receipts, and compare with what you were billed.
When something looks wrong
- A check
failed— send the complete verifier output to linkex. The records disagree with their own commitments; that is theirs to explain, immediately. - A check
skippedthat you need — read the skip reason first; if it's something you're entitled to that wasn't provided, request it. - A
4XXfrom an endpoint — the response body names the parameter to fix (for example,stream is required, e.g. stream=ch:42); the endpoints are built to be self-explaining.
If you dispute a single charge, request a single-dispute proof bundle — verifiable offline in seconds. The conversation then starts from a shared, checkable artifact instead of two spreadsheets.
Trust model and boundaries
What Open Tally does not claim — the residual gap in completeness, the limits of cryptographic proof, and where engineering and process must carry the argument.
Proof bundles and sampling
The artifacts handed over when questions arise — single-dispute bundles, period bundles, deterministic sampling with stated miss rates, and full recomputation.