To add a blockchain timestamp feature, compute a SHA-256 hash of each file on your servers, write that hash to a public blockchain, and store what comes back. Then give each user two things: a certificate page anyone can check, and a file that verifies the proof without your app or your vendor. Writing the hash to the chain is the small part. Most of the work is in everything around it.

This page covers what the feature has to include, what it proves, and what you take on if you build it yourself or buy it.

What the feature is

A blockchain timestamp feature, also called proof of existence, has five parts:

1. Hash the file. SHA-256 turns any file into a 256-bit fingerprint, written as 64 hex characters. Change one byte of the file and the hash changes completely. You compute it on your servers, so the file itself never has to go anywhere else. 2. Anchor the hash. The hash goes into a transaction on a public blockchain. The block that includes the transaction carries a time set by the network, not by your database. 3. Keep the receipt. Store the transaction id, the chain, the hash and the anchor time next to your own record of the file. 4. Show the user a certificate. This is a page that shows the hash, the transaction and the time, and that someone outside your app can open and check. 5. Keep a portable bundle. This is a small file holding everything needed to check the proof again later, with no help from you or any vendor.

If you skip parts four and five, your users end up with a transaction id they don't know how to read and a proof that only works while your app is running.

What it proves, and what it doesn't

An anchored hash proves one thing: this exact file existed no later than the time of the anchor. Anyone can check that by hashing the file again, comparing the result to the recorded hash, and finding the transaction on the chain.

It doesn't prove who made the file. It doesn't prove when the file was created, only that it existed by the anchor time. It isn't copyright registration and gives no legal rights. And it can't be added after the fact: a file anchored today proves nothing about last month.

Put these limits in your product copy. A user who reads "proof of ownership" on your upload screen will be badly let down the first time they actually need it.

The build-it-yourself path

Here's what building it in-house involves.

A wallet and gas. Every anchor is a transaction, and every transaction pays a fee in the chain's native token. Someone has to keep the wallet funded, watch the balance, and deal with failed or stuck transactions.

A way to put the hash on chain. On Bitcoin that usually means an OP_RETURN output. On an EVM chain such as Polygon, it means calldata or a small contract you deploy and maintain. Either way you decide the data format, and that format becomes something your verifier has to read for good.

A key you have to guard. The signing key can spend the wallet's funds and write under your name. It needs storage, access control, rotation and a plan for when it leaks. Many teams end up putting it on a separate signer machine so the web servers never hold it.

Batching and retries. One transaction per file is simple but slow and expensive at volume. Batching means aggregating hashes, often with a Merkle tree (a structure that rolls many hashes into one, with a short path that proves any single hash is inside it). Now each proof also has to store its path. Retries need idempotency, so a timed-out request doesn't anchor the same file twice.

Telling your app when the anchor lands. Anchoring isn't instant. You need a job that watches the chain and updates records, plus a way to push the result to the rest of your system.

A verifier you write and host for good. This part is easy to underestimate. Every certificate you issue points at a verify page you have to keep running for as long as anyone might rely on it. If you also want proofs to work without you, you need to publish the bundle format and an offline checker, and keep both compatible with every proof you've ever issued.

None of this is hard on its own terms. It's the kind of infrastructure that's cheap to start and expensive to own.

The bare timestamp is cheap

A timestamp alone isn't where the cost is. OpenTimestamps is an open-source protocol that timestamps hashes on Bitcoin through calendar servers and Merkle aggregation, and it's free to use. You run the client and keep the resulting .ots files. There's no hosted certificate page and no vendor.

What a platform pays a vendor for isn't a better timestamp. It pays for the parts users and integrators touch: a certificate page anyone can open, a signed webhook when the anchor lands, a bundle in an open format, a public verification page, and an API that handles retries and your own record ids.

The buy path: what to look for in an API

When you look at a hosted anchoring API, check the parts that cost you the most to build:

  • Batch submission with your own ids. You should be able to send many hashes in one call, each tagged with the id from your database, and resend safely without creating duplicates.
  • A signed callback. The service should notify you when each anchor lands, and you should be able to check that the notification really came from the service.
  • A bundle in an open file format. Your user should be able to check the proof with a tool that doesn't call the vendor.
  • A user-facing certificate. This is a page you can link from your product, ideally one that shows your product's name.
  • A verification path that survives the vendor. Ask what your users still hold if the service goes away.

How ProofLedger's API covers each part

ProofLedger works the same way for every file type: it hashes the bytes with SHA-256, anchors the hash on Polygon in its own public transaction, and returns a proof. Anchoring usually completes within a minute. Only the hash is sent. The file stays on your servers.

Submitting hashes. POST /api/v1/proof takes {"sha256": "<64 hex chars>", "filename": optional label, "external_id": optional record id} with a Bearer sk_ key from Account > API Keys. It returns 201 with the proof's id, status, certificate URL and verification URL. POST /api/v1/proofs/batch takes up to 100 hashes in one call, each with its own external_id. They're checked first and written together. Resending an external_id returns the existing proof instead of a new one. There's also an optional Idempotency-Key header on the POST endpoints: a resend with the same key and body within 24 hours returns the stored successful response with Idempotent-Replayed: true.

Knowing when the anchor lands. Register an https URL with POST /api/v1/webhooks. When a proof's Polygon anchor lands, ProofLedger POSTs a proof.polygon.anchored event signed with HMAC-SHA256 in the ProofLedger-Signature header, using that endpoint's secret. Failed deliveries are retried seven times over almost two days. After that the endpoint is switched off and the account gets an email. Webhooks only cover proofs created after the endpoint was registered.

Reading back. GET /api/v1/proof/:id returns status and the chain transaction. GET /api/v1/proofs looks proofs up by external_id, or lists the proofs anchored since a given time, cursor paged, which is useful for reconciling your records with the chain.

The bundle. GET /api/v1/proof/:id/bundle returns the hash, chain, transaction id and anchor time in the verify-proof file format. The same bundle is included in every anchored webhook payload, so you can store it the moment the anchor lands.

Verification without ProofLedger. The verify-proof package checks a file against its bundle on the user's own machine, with no network call. Anyone can then look up the Polygon transaction on a block explorer. Separately, GET /api/v1/verify?hash=<sha256> is public and needs no key, and every proof also gets a public verify page.

The user-facing parts. One script tag embeds a certificate card or a verify widget in your own pages. The widget hashes a dropped file in the visitor's browser and checks only the hash. An SVG status badge works in emails and READMEs. A company recording proofs for its own users can apply to have its product name on certificates, worded exactly "Recorded through <Partner> · Anchored by ProofLedger". Each name is approved by hand after an impersonation check, and it's copied onto each proof when the proof is created.

Limits. Every keyed call is limited to 120 requests per minute per key. Responses carry X-RateLimit headers, and calls over the limit get 429 with Retry-After. Plans and monthly allowances are listed at https://proofledger.io/pricing.html.

If you'd rather run the server yourself, ProofLedger Community is the open-source proof core as a Node and SQLite server with the same v1 API shapes. It anchors with your own Polygon key and writes the same transaction shape, so verify-proof checks its bundles the same way. You then own the wallet, the key, the backups and keeping the verify pages online.

The quickstart is at proofledger.io/platforms. The API docs are at proofledger.io/api.html, and the OpenAPI spec is at /openapi.json.