You have a file, and you need to show that this exact version existed no later than a given date. Your own file system's "created" and "modified" dates will not do it: anyone with a terminal can set them to anything. What you need is a record of the file, or of its fingerprint, held somewhere you do not control, made at a time you can point to, and checkable by someone who does not trust you. There are four ways to get one. They differ in who holds the record and in what the record shows.
First, what any method can show
Every method below works on the same claim: a document with this exact content existed by time T. None of them shows who wrote it, when it was first written, or that what it says is true. If you held the document for a year before recording it, the record shows the later date. That is the limit of a timestamp, whatever produces it. Whether a court accepts any of these records is for the court and the lawyers; this post is about what each record shows technically.
Option 1: Someone else already has a copy
If you emailed the file, uploaded it to a shared system, or filed it with an agency, that copy sits with its own timestamp in someone else's logs. This is often the best record you already have, and it cost nothing extra.
The weakness is that you are now relying on another party's records and their willingness to produce them. Mail servers rotate logs. A counterparty may not cooperate. A cloud provider's timestamp is only as good as your ability to export it with the file still attached. It also only works backwards, for things you happened to share. It is not a process you can run on every file going forward.
Option 2: A notary or an RFC 3161 timestamp authority
A notary records that a document was presented on a date. The digital equivalent is a Time-Stamp Authority under RFC 3161: you send the file's hash, the authority signs it together with the current time, and you keep the signed token. OpenSSL has both ends built in:
openssl ts -query -data contract.pdf -sha256 -cert -out request.tsq
curl -s -H "Content-Type: application/timestamp-query" --data-binary @request.tsq https://<tsa-endpoint> -o response.tsr
openssl ts -verify -in response.tsr -data contract.pdf -CAfile tsa-chain.pem
What the token shows: this hash was presented to this authority at this time. Who holds the record: you hold the token, and the authority's signing key and certificate chain vouch for it. Anyone checking later needs that chain, and needs the key to have been sound at signing time. That is one specific party to trust, and one key to keep track of for as long as the record matters.
Option 3: Mail it to yourself
Seal a copy in an envelope, post it to yourself, never open it. The postmark is the date. It is cheap, and it is weak. The postmark is on the envelope, not bound to the contents; an envelope can be opened and resealed; and nothing about it can be checked without physically handling the original. It is also not a copyright registration and does not substitute for one. If this is all you have, you have very little.
Option 4: Anchor the hash on a public blockchain
Here the mechanism matches the question closely. Instead of trusting one person, one company or one key, you publish the document's fingerprint into a transaction on a public chain, where independent nodes each keep a copy of every block. The document itself never goes anywhere. The fingerprint is a SHA-256 hash: 64 hex characters that change completely if one byte of the file changes.
import hashlib
def sha256_of(path):
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
print(sha256_of("contract.pdf"))
# b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
Once a transaction carrying that hash is in a block, the block's time is the record. Later, anyone with a copy of the document can hash it, find the transaction on a block explorer, and compare. A match shows the document existed in exactly this form by that block's time. A mismatch means the document changed or was never there.
Who holds the record: the chain does, in public. What you hold is the transaction id and the hash. What it shows: existence of this content by the anchor time, nothing more. The record is tamper-evident rather than untouchable: a changed file simply stops matching, and anyone can see that it does.
Doing it through an API
ProofLedger is proof of existence as an API: send the hash, get a Polygon-anchored certificate anyone can verify without us. Each proof is its own Polygon transaction, usually within a minute.
curl -X POST https://proofledger.io/api/v1/proof \
-H "Authorization: Bearer sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"sha256": "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c",
"filename": "contract.pdf",
"external_id": "contract-2026-0187"
}'
The reply is 201 with an id, polygon_status (PENDING, then ANCHORED), certificate_url and verification_url. Sending the same external_id again returns the existing proof with 200 and already_existed: true, so a retried job does not create a second record. Once anchored, GET /api/v1/proof/{id} carries chain_tx, polygon_anchored_at and explorer_url, and GET /api/v1/proof/{id}/bundle returns one JSON document with the hash, chain, transaction id and anchor time. Keep that bundle next to the file.
What you hold afterwards is the same as in option 4, because it is option 4: a hash and a public transaction. The certificate page and the public verify endpoint (GET /api/v1/verify?hash=, no key needed) are conveniences for showing the record to someone. They are not the record.
Choosing
Use option 1 whenever it already exists; an old email is evidence you did not have to plan for. Use option 2 when the other side will specifically ask for an RFC 3161 token and you are prepared to keep the authority's chain. Skip option 3. Use option 4 for anything you are producing now and might need to show later, because the record does not depend on you, on the service that anchored it, or on one signing key staying sound.
Be precise about what you then have. The anchor shows existence by a time. A signature, if you add one, shows who. Whether the content is true is a separate question that no timestamp answers.
To check a proof without ProofLedger, hash the file, compare it with the hash in the bundle (the open-source verify-proof tool does this offline, on PyPI and npm), and look the transaction id up on any Polygon block explorer. API reference: https://proofledger.io/api.html