Guides

Guides · Part 3 of 5

Verify a record

Verification is the half of Label 309 that asks nobody's permission. Given a Cardano transaction reference, you can confirm a record yourself — against the public chain, through an explorer you choose. There is no login, and nothing about the result depends on whoever published it.

With the CLI

Install the cardanowall binary, then point it at a transaction:

cardanowall verify 3b9f…c1a2

It resolves the transaction through a public Cardano explorer, structurally validates the record, checks any authorship signatures, confirms the record is settled, and prints a verdict. The exit code carries that verdict, so it drops straight into CI:

Exit codeMeaning
0valid
1integrity failure — a check did not pass
2network error — couldn't reach an explorer
3pending — not enough confirmations yet
4+verifier couldn't run — a host-side failure

Add --json for a machine-readable report, and keep every network hop under your control by pointing at your own infrastructure:

cardanowall verify 3b9f…c1a2 \
  --cardano-gateway https://your-koios-instance/api/v1 \
  --threshold 20 \
  --json

If the record is sealed to you, hand the verifier your key and it will decrypt the payload and recompute the plaintext hash:

cardanowall verify 3b9f…c1a2 --secret-key-stdin

Prefer --secret-key-stdin, --secret-key-file, or the CARDANOWALL_RECIPIENT_KEY environment variable over a bare --secret-key flag, so the key never lands in your shell history.

With the TypeScript SDK

The verifier the CLI uses ships in the SDK. It needs no client, no base URL, and no key — verification is gateway-agnostic:

import { verifyTx } from '@cardanowall/sdk-ts/verifier';

const report = await verifyTx({ txHash: '3b9f…c1a2' });

console.log(report.verdict); // 'valid' | 'pending' | 'failed'

if (report.verdict !== 'valid') {
  console.error(report.validation.issues, report.record_signatures);
}

verifyTx returns a full VerifyReport: the verdict and exit code, the resolved block time and slot, the structural validation summary, record_signatures and merkle_checks, and an http_calls log of every outbound request it made — so you can prove to yourself it never contacted the publisher.

To verify a record sealed to you, pass your secret key for the relevant item:

const report = await verifyTx({
  txHash: '3b9f…c1a2',
  decryption: [{ itemIndex: 0, recipientSecretKey: mySecretKey }],
});

With the Python SDK

cardanowall-sdk is a byte-for-byte twin of the TypeScript verifier — the same checks, the same verdict:

import asyncio
import cardanowall

report = asyncio.run(cardanowall.verify_tx(cardanowall.VerifyTxInput(tx_hash="3b9f…c1a2")))
print(report.verdict)

With the Rust SDK

The cardanowall crate carries the same verifier. verify_tx is synchronous — it owns a blocking transport — and returns the same VerifyReport:

use cardanowall::verifier::{verify_tx, Verdict, VerifyTxInput};

let report = verify_tx(&VerifyTxInput::new("3b9f…c1a2"));

println!("{}", report.verdict.as_str()); // "valid" | "pending" | "failed"

if report.verdict != Verdict::Valid {
    eprintln!("{:?}", report.validation.issues);
    eprintln!("{:?}", report.record_signatures);
}

To verify a record sealed to you, attach your secret key for the relevant item. The input fields are public, so build on top of VerifyTxInput::new:

use cardanowall::verifier::{verify_tx, Decryption, VerifyTxInput};

let mut input = VerifyTxInput::new("3b9f…c1a2");
input.decryption = Some(vec![Decryption::Recipient {
    item_index: 0,
    recipient_secret_key: my_secret_key, // Vec<u8>
}]);

let report = verify_tx(&input);

Why this needs no trust

Every check runs from public data and an explorer you choose. The people who published the record cannot influence the outcome — and if they disappeared tomorrow, your verification would still work exactly the same.