9 min read
Publish Your First Proof of Existence on Cardano
Your first Label 309 proof can be a hash-only record: hash a file, get a price quote from a gateway, publish the digest on Cardano, and keep the transaction hash. Here is the full workflow.

The simplest Label 309 proof is a hash anchored on Cardano.
You take a file, compute its cryptographic hash, publish that hash in a Label 309
record under Cardano metadata label 309, and keep the resulting transaction
hash. Later, anyone with the original file can recompute the hash and confirm
that the matching commitment was on chain no later than the transaction's block
time. They do not need your server, your domain, or your identity to check it —
only the transaction reference and a public Cardano explorer.
That is the first level of Proof of Existence. Everything else builds on it. This
guide walks through publishing one, mostly from the cardanowall command-line
tool, and ends with how to confirm it actually worked.
What are you actually publishing?
You are not publishing the file itself when you create a basic proof.
You are publishing a commitment to the file: its digest. A digest is a fixed-size cryptographic fingerprint. If the file changes by a single byte, the digest changes completely. That property is what makes a hash a reliable stand-in for the exact bytes.
A hash-only proof is a good fit for things like:
- contracts and invoices;
- release artifacts and build manifests;
- AI outputs and dataset snapshots;
- policy documents and evidence packages;
- checksums another system already produced.
The proof does not reveal the file contents. It reveals only the hash, the hash algorithm you chose, and whatever optional metadata you decide to include in the record. For more on which fields land on chain, see what goes on the blockchain.
What do you need before you publish?
Publishing needs a gateway. Verifying does not.
Verification runs entirely from public chain data. Publishing is different: something has to build and submit the Cardano transaction, pay the network fee, handle confirmation, and — if you store files off-chain — pay the storage cost. A Label 309 gateway is the service that does all of that. The open-source gateway and the tooling around it are gateway-agnostic, so you point the tools at whichever gateway you hold a key for.
For your first proof, you need:
- a file or a precomputed digest;
- a Label 309 gateway base URL;
- an API key or short-lived account token for that gateway;
- enough balance on your gateway account;
- optionally, an Identity Seed, if you want to sign the record.
If you use the hosted CardanoWall gateway, CardanoWall runs the gateway account and the prepaid balance for you. If you run your own gateway, you fund its Cardano and storage wallets yourself. Either way, publishing costs money because real fees are paid on your behalf — the topic of why publishing has a price.
Why is the workflow quote first, then publish?
A gateway should never silently publish and surprise you with a bill. So every publish has the same two-step shape: lock a price, then submit.
- Build or estimate the record.
- Ask the gateway for a quote.
- Receive a quote id and a price breakdown (network fee, storage, service margin).
- Submit the finalized record with that quote.
- Receive a gateway record id immediately, while the transaction is still being submitted.
- Track status until the transaction is confirmed on chain.
- Verify the result independently.
A quote locks the price for a limited window — currently 15 minutes. If it expires before you publish, you request a new one; the price may move if exchange rates moved, but nothing else changes.
This two-step pattern is what makes automation safe. Your script can log the quote, enforce its own spending policy, and only then publish — so a price spike or a fat-fingered batch can never run away with your balance.
Publish a file with the CLI
For a local file, the command-line flow is intentionally small:
cardanowall submit \
--file ./contract.pdf \
--base-url https://your-gateway.example \
--api-key "$CARDANOWALL_API_KEY"The CLI hashes the file, builds the Label 309 record, asks the gateway to quote
and publish it, and prints the result. --base-url and --api-key also read
from the CARDANOWALL_BASE_URL and CARDANOWALL_API_KEY environment variables,
so they drop out of the command in CI.
For repeat use, save the gateway as a named profile instead of passing the endpoint every time:
cardanowall gateway add prod --base-url https://your-gateway.example
cardanowall gateway use prod
cardanowall submit --file ./contract.pdfThe cardanowall binary is a single, self-contained native tool with no runtime
to install. Install it from
crates.io with cargo install cardanowall-cli (the crate is cardanowall-cli; the installed command is
cardanowall), or build it from the open-source repository at
github.com/cardanowall.
How do you publish a hash you already have?
Sometimes the digest already exists — from a build pipeline, a container registry, a release process, or a data archive. In that case, publish the digest directly, with no file involved:
cardanowall submit --hash <64-hex-digest>The default hash mode is sha2-256. Pass --alg blake2b-256 when you need that
algorithm instead. The record records which algorithm you used, so a verifier
knows how to recompute the digest later.
Publishing a precomputed hash is also the right move when the source file is too large, too sensitive, or too tightly controlled to move through a general-purpose tool. The only thing that matters is that the exact bytes and the exact hashing process stay reproducible — otherwise no one can recompute a matching digest.
Should you sign the record?
Sign the record when you want to prove that a specific Label 309 identity vouched for it.
A hash-only proof says: these bytes existed by this time. A signed proof adds: and this signing key stands behind this exact record. That extra claim matters for company release records, official archives, CI/CD pipelines, legal evidence workflows, AI provenance logs, and any long-lived public publisher identity.
Signatures are always optional. An unsigned proof is still a complete, fully verifiable proof of existence — Label 309 is issuer-agnostic by design, and a verifier never has to trust the publisher. Signing just answers a different question: who vouches for the record, not whether the bytes existed.
The Identity Seed must never be sent to the gateway. The CLI and SDK are built so
signing happens locally and only the finished signature travels. Supply the seed
through --seed-stdin or --seed-file rather than a bare --seed argument,
because command-line arguments leak through shell history, process listings, and
CI logs:
cardanowall submit --file ./release-manifest.json --seed-stdinShould you attach the file, or just the hash?
You have three choices, in increasing order of what you commit on chain.
Hash only. The smallest and most private proof. It is enough when you already know the file will be preserved somewhere you control. The record carries the digest and nothing about retrieval.
Hash plus a content-addressed link. Attach an ar:// (Arweave) or ipfs://
(IPFS) URI so verifiers can fetch the bytes later. The hash still decides whether
the fetched bytes match — a content-addressed URI binds the bytes to the link
itself, so a verifier never has to trust the gateway, DNS, or TLS to know it
fetched the right file.
Sealed. Encrypt the file, store the ciphertext off-chain, and put the sealed envelope in the record. This is the path for confidential records, delivery to a named recipient, and recovering the content later if your local copy is lost.
For a first proof, start with hash only. Add signing, off-chain storage, Merkle batching, or sealed delivery when a real use case calls for it.
How do you know it actually worked?
Do not stop at "the gateway accepted it." The proof is complete only when the transaction is on chain and verifies.
When you publish, the gateway hands back a record id right away and the transaction hash fills in asynchronously once the transaction is built and submitted. So after publishing, keep:
- the Cardano transaction hash;
- the gateway record id, if you used a gateway;
- the original file or digest;
- the signing key's public identity, if you signed;
- any Merkle leaf list or inclusion proof, if you batched;
- any recovery material, if the proof is sealed.
Then verify the transaction the same way any third party would — from the public chain, with no gateway involved:
cardanowall verify <tx-hash> --jsonA valid verdict is the finish line. The other verdicts tell you what to do
next:
pending— the transaction has not settled deeply enough yet. Wait for more confirmations and retry.unverifiable— no fault in the record, but a required check could not run. Check your data sources, off-chain storage availability, and network policy.failed— a real, record-attributable problem. Investigate the record itself.
The split between failed and unverifiable is deliberate: failed means the
record is wrong, while unverifiable means the verifier could not finish a
check. For the full verification flow, see
verify a Label 309 record.
What should a UI show after publishing?
A good interface shows more than the word "published." For a first proof, surface:
- the short transaction hash, with a copy button;
- the full transaction hash in the detail view;
- the hash algorithm and the digest;
- the publication status;
- the block time, once confirmed;
- the verification verdict;
- whether the record was signed;
- whether files were attached or sealed;
- whether any checks were skipped.
That makes the proof understandable without forcing anyone to read the specification.
What can go wrong when publishing?
Most publishing failures are operational, not mysterious. The account may be out of balance. The quote may have expired. The record may be too large for a Cardano transaction. An uploaded file may fail to store. The Cardano transaction may fail permanently — in which case a well-built gateway reverses the charge itself, so you are only billed for what lands on chain. Or the gateway's funded wallet may simply need attention.
A serious publishing workflow handles retries idempotently. A gateway will dedupe a publish retry by the record's exact bytes — resubmitting the identical record returns the existing result instead of spending twice — and accepts an idempotency key on upload batches so a redelivered upload is replay-safe. In a user-facing product, design the retry path before your first real customer hits a network timeout, not after.
If you are wiring this into a pipeline, using the CLI in automation goes deeper on JSON output, exit codes, and safe secret handling.
What does your first proof not prove?
A proof of existence is precise about what it claims, which means it is also precise about what it does not.
- It does not prove ownership.
- It does not prove authorship — unless you sign it and can tie the signing key to the claimed identity.
- It does not prove the file is true, lawful, or original.
- It does not preserve the file, unless you store it somewhere durable.
What it does prove is exact and durable: the precise bytes matching the committed hash existed no later than the transaction's block time, and any optional signatures, storage checks, or sealed-content checks verified according to the verifier's policy.
That is enough to be genuinely useful, and precise enough to be trusted. For the fuller boundary of what a timestamp can and cannot establish, see what a proof does not prove.
Further reading
- Verify a Label 309 record — the trustless, account-free other half of the workflow.
- Why publishing has a price — what the fee pays for.
- Use the CLI in automation — JSON output, exit codes, and secrets in CI.
- What goes on the blockchain — the fields a record actually carries.
- The open standard and reference implementations: label309.org and the source at github.com/cardanowall.