Back to News & Insights
Web Development August 22, 2026 · 4 min read

I built an e-signature app that charges you for storage, not signatures

The bill that made no sense A signature is about 400 bytes of JSON and a hash. Every big...

I built an e-signature app that charges you for storage, not signatures

Every big e-signature product will charge you somewhere between $1 and $4 to store those 400 bytes. They call it an "envelope". Run out of envelopes on the 22nd of the month and your deal waits until the 1st. I have watched a real contract sit still because a counter hit zero.

The expensive part is the other thing. A 4 MB PDF sitting in storage for seven years, backed up and replicated, costs real money every month. That part is free. It is a checkbox on the feature list.

So the pricing is backwards. It charges for the cheap thing and gives away the expensive one.

I built Putmysign the other way around. Unlimited documents, unlimited recipients, unlimited signatures, on every plan. You only pay if you want the files kept.

Free keeps your PDFs for 5 days. Pro is $19 a month and keeps them forever. The audit trail is kept forever on both, because it is a few kilobytes and it is the whole point of the product.

That one pricing decision shaped almost every technical choice underneath. That is the interesting part. Deleting files is a feature, so it has to actually happen

If I promise free files are gone in 5 days, "we will get to it eventually" is not good enough. A scheduled job walks every document past its expiry date and removes the file from storage, along with every cached page image made from it.

But it deletes the file, not the record. The row stays. The audit trail stays. The hashes stay:

So five days later the PDF is gone from my storage and I still cannot lie about what happened. If you kept your own copy, you can hash it and check it against a record I cannot quietly change.

Throwing away the file while keeping the proof turned out to be a nice property. I did not design it. It fell out of the pricing.

The worst bug in this area was a quiet one. A signing link can outlive the file it points to. The recipient clicks a link that is perfectly valid, and lands on nothing. So link expiry is capped to the retention window:

Two separate clocks on the same object will drift apart sooner or later. Make one of them depend on the other. Recipients never make an account

A signup wall in the middle of someone else's contract is the biggest reason paperwork stalls. It mostly exists so vendors can count seats.

So the signing link is the login. It is an HMAC over the document and the recipient, built from a server-only secret. Only the hash of the token is stored:

Store the hash, not the token. If my database leaks tomorrow, nobody gets a working signing link out of it. Same idea as hashing passwords, applied to a URL. One row per document

A signing session is a burst of tiny writes. Opened. Viewed page 3. Signed field 2. IP recorded. All of it against one document that is only ever read as a whole.

Splitting that across six tables buys me joins I never run. So each document is one JSONB column holding everything, with the fields I actually filter on copied out into real indexed columns: owner, status, updated date, expiry date, purge date. A GIN index on the JSON handles signing-link and "shared with me" lookups.

The real risk with a single row is two people signing at the same moment. Last write wins, one signature disappears. I fixed it the boring way, with SELECT ... FOR UPDATE inside a transaction.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation