You have a file and you need to show it existed by a certain date. Every method for doing that comes down to two questions: what do you hold afterwards, and what does the person checking it have to trust? This post walks through the methods in use today by those two questions, so you can pick one your reader can follow without your help.

What a timestamp on a hash can show

Each method below starts the same way. You compute the SHA-256 hash of the file, a 64-character fingerprint that changes completely if one byte changes, and you get that hash recorded somewhere with a time. Later, anyone with the file recomputes the hash and compares it with the record.

That shows one thing: a file with this exact hash existed by the recorded time and has not changed since. It does not show who made the file, what the file depicts, that its contents are true, or that nothing was edited before the hash was taken. It is a timing and integrity record, not an authorship record. Keep that limit in mind when reading any vendor's page, including ours.

Metadata you control

File system dates, cloud upload dates, email headers and EXIF fields are what most people reach for first.

  • What you hold: the file and whatever system it sits in.
  • What a third party has to trust: you. Every one of those dates lives in a system you control and can be changed by whoever controls it.

That is fine for finding a file. It is not a record someone else can check.

Notarization

A notary witnesses a person signing a document and records who appeared and when they signed.

  • What you hold: the signed document with the notary's seal, and the notary's journal entry.
  • What a third party has to trust: the notary's record of that appearance.

A notary does not hash the file and says nothing about whether the bytes changed later. Notarization answers "who signed this and when did they sign", which is the right question for a deed or an affidavit, and the wrong one for "did this file exist in this form by this date".

RFC 3161 timestamps

RFC 3161 is the IETF standard for signed timestamps. Your client sends the hash to a timestamping authority; the authority signs the hash together with the time from its own clock and returns a token.

openssl ts -query -data record.pdf -sha256 -cert -out record.tsq
openssl ts -verify -data record.pdf -in record.tsr -CAfile tsa-chain.pem
  • What you hold: the token (.tsr) and the authority's certificate chain.
  • What a third party has to trust: the authority's key, its clock and the certificate chain the key sits under. The check runs through OpenSSL or similar tooling, and through PKI rather than a public ledger.

RFC 3161 is well established in document signing and regulated record keeping. If the certificate chain is one your reader already recognises, it works well. If not, they have to obtain and trust it first.

Writing the hash to a public chain yourself

You can put the hash into a public blockchain transaction with your own wallet. On Bitcoin that is an OP_RETURN output; on an EVM chain such as Polygon it is the data field of a transaction. The block that includes the transaction carries a time no single party sets.

  • What you hold: the transaction id and the original file.
  • What a third party has to trust: the chain itself. They recompute the hash, open the transaction on any block explorer, confirm the hash is in it and read the block time. No service needs to exist for the check to work.

The cost is operational: a funded wallet, fee handling, and a system of your own that records which transaction holds which file's hash. There is no certificate and nothing a non-technical reader can open.

OpenTimestamps is the open protocol version of this. Calendar servers collect hashes, combine them in a Merkle tree and commit the root to Bitcoin. You keep an .ots file that traces your hash up to that root. The reader trusts Bitcoin and the arithmetic, but needs the OpenTimestamps client, and a node or a calendar server, to run the check.

Hosted anchoring

A hosted service takes the hash, writes the transaction for you and hands back a record you can store next to the file. ProofLedger is one. Each proof goes into its own Polygon transaction, usually within a minute. (ProofLedger also anchored some proofs on Bitcoin before 15 October 2026; since then every proof is anchored on Polygon only.)

  • What you hold: the proof bundle (hash, chain, transaction id, anchor time) and the public transaction it points to.
  • What a third party has to trust: the chain, plus the service having written your hash faithfully. They do not have to take that on faith: the bundle names the transaction, and any block explorer shows it.

Submitting a hash is one call. The file never leaves your machine; only the hash goes, with an optional file name and your own record id:

curl -X POST https://proofledger.io/api/v1/proof \
  -H "Authorization: Bearer $PROOFLEDGER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sha256":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2","filename":"record.pdf","external_id":"record-2026-0147"}'

A 201 returns the proof id, polygon_status (PENDING until the transaction lands, then ANCHORED) and a certificate_url. Once anchored, fetch the bundle and keep it with the file:

curl -H "Authorization: Bearer $PROOFLEDGER_API_KEY" \
  "https://proofledger.io/api/v1/proof/42/bundle?download=1" -o record.pdf.proof.json

Anyone can also look a hash up without a key at GET /api/v1/verify?hash=<sha256>. That endpoint and the certificate page are conveniences. The record is the transaction and the bundle.

C2PA, which answers a different question

C2PA Content Credentials put signed provenance inside the file: which device or tool produced it and what edits followed. That answers "where did this come from", not "when did it exist", and because the manifest lives in the file it is lost when the file is re-encoded or converted. A hash recorded outside the file is unaffected by that. The two pair well; neither replaces the other.

Checking a proof without the issuer

For a bundle in the verify-proof format, the open-source tool checks the file against it offline:

pip install verify-proof
verify-proof hash record.pdf
verify-proof verify record.pdf --proof record.pdf.proof.json

It prints VERIFIED or FAILED and exits non-zero on failure. It does not read the chain. For that, take the tx_id from the bundle and open it on any Polygon block explorer: the transaction should exist and its block time should match the bundle's anchor time.

For an RFC 3161 token, the openssl ts -verify line above does the equivalent, given the authority's chain.

Choosing

Pick by who will read the record and what they can check alone. Metadata you control asks them to trust you. Notarization answers an identity question. An RFC 3161 token asks them to trust a certificate chain and run PKI tooling. A hash you wrote to a chain yourself asks them to trust only the chain, at the price of running the operation yourself. A hosted anchor gives you the same kind of public transaction plus a bundle and a page, and the reader can skip the service entirely and go to the explorer. Whether any of this persuades a court is for the court and the lawyers; what the methods differ on is what a reader can confirm with their own hands.

To check a ProofLedger proof without ProofLedger: hash the file, compare it with the bundle using verify-proof, and open the bundle's transaction id on any Polygon block explorer. The API is documented at https://proofledger.io/api.html.