Three checks, reported separately.
A verification answers three independent questions. Each is reported on its own. A failure on one axis does not invalidate the others, the verify page shows all three so you can reason about the cause.
Was this root ever sealed?
A lookup on root_hash against the Neon Postgres ledger. Tells you the Authority observed this exact root at the recorded timestamp.
SELECT * FROM seals WHERE root_hash = ?Did the Authority sign it?
Ed25519 verify of the stored signature against the current or any historical public key from /.well-known/bitseal-authority.json.
verify(sig, root || LE_f64(ts), pubkey)Do the leaves still hash to the root?
Re-fold the merkle_tree array using the spec and compare against the stored root_hash. Catches tampering with the leaves relative to the signed root.
BLAKE3(left || right) -> parentWhy three axes, not one checkmark
Collapsing the answer to a single green tick hides the interesting cases. A seal can be in the ledger but have an invalid signature (the Authority's key got compromised and was revoked). The signature can be valid but the leaves don't fold to the stated root (tampering after signing). The cryptography can check out but the ledger has no record of it (a signature-only proof with no timestamping witness).
Each axis answers a different question and fails for different reasons. The verify page reports them separately so you can see which trust property survived and which one didn't.
Result shapes
All three pass
The root is in the ledger, the signature verifies against the Authority's public key, and the leaves fold to the root. This is the intended happy path, the seal is fully valid.
Ledger found, one axis open
The ledger entry exists but the signature check was inconclusive (for example, the signer key ID points to a revoked historical key still within its valid-for-verification window), or a leaf array was not provided so the tree could not be re-folded. Partial verification, readable, not decisive.
Validation failed
No record of the root, or a signature that does not verify. The seal is not trusted. Double-check the root hash for transcription errors before declaring tampering.
Verify without BitSeal
Nothing on this page requires a network call to BitSeal. The public key is at /.well-known/bitseal-authority.json. Every signature payload is the 40-byte root || LE_f64(ts). The Merkle fold is the merkle-blake3-64k-v1 spec documented in Architecture. Any BLAKE3 and Ed25519 library on any platform can verify a seal offline, years after the service is gone.
Bonus: Bitcoin anchor
Every seal created since April 2026 is additionally stamped to four public OpenTimestamps calendars at sealing time. Once any of those calendars includes its aggregated merkle root in a Bitcoin block (typically 1 to 6 hours after sealing), a daily sweep upgrades the stored proof to its Bitcoin-anchored form and records the block height and block time on the ledger row. The verify page then renders a deep-link to mempool.space for that block.
This is a bonus, not a fourth axis. A seal is cryptographically valid under the three axes above even when the Bitcoin anchor is still pending or absent. The anchor exists to give verifiers an independent witness that the seal existed before a specific Bitcoin block was mined, without having to trust BitSeal, the calendars, or any single third party.
The BitSeal SDK v0.3.0 ships a --ots flag that parses the upgraded proof bytes locally, extracts the Bitcoin block header attestation, and compares the committed merkle root against the real block header fetched from mempool.space (with blockstream.info as a fallback). A passing result depends only on Bitcoin and the BitSeal signing path, never on a live BitSeal API call.
# Three axes + Bitcoin anchor, against a sealed root.
python verify.py --root <64-hex-root> --otsThe three reported anchor states are upgraded (Bitcoin block confirmed, full check runs), pending (calendars accepted but Bitcoin has not yet confirmed, re-run later), and none (seal predates April 2026 or all calendars were unreachable at sealing time). The three-axis result is unaffected by the anchor state.