Build vs buy
Rolling your own licensing: what it actually costs
Building a licensing layer from scratch is doable. The question is whether it is worth the time. Here is a concrete breakdown of every piece you have to maintain, with honest estimates on each one.
What you have to build (and keep running)
Each row is a system you own end to end if you roll your own. The Paperkey column shows what the managed version gives you on day one.
| What you have to build (and keep running) | Build it yourself | With Paperkey |
|---|---|---|
| Key generation, format, rotation | Write a generator, decide on a prefix scheme, handle rotation without invalidating live keys. Add a CSPRNG-backed format, store hashes (never plaintexts). Build a migration path for old key formats. 2-4 days. | Prefix-namespaced keys out of the box. Hash storage enforced. Rotation is a single API call. |
| Rate limiting | Per-IP limiter on validate, per-key limiter on activation, separate tighter limit on auth endpoints. Redis or in-memory depending on your infra. Handle burst, 429 responses, Retry-After headers. 1-2 days. | Per-IP and per-key rate limits ship by default. Auth endpoints have a separate stricter budget. |
| Activation edge cases (machine swap, reinstall, seat limits) | Track fingerprints per license, handle the "user reinstalled the OS" support ticket, decide how many machines per seat. Implement deactivation, cap enforcement, and the grace period for seat overflows. 3-6 days; ongoing support burden. | Seat cap, per-machine fingerprint slots, deactivation endpoint, and grace period are all built in. Support tickets on edge cases go to us. |
| Webhook signing (HMAC, retries, dedup) | HMAC-SHA-256 per delivery, idempotency key in the header, retry queue with backoff, auto-pause after N failures, per-delivery log, 5-second timeout. 2-3 days to get right; tricky to test. | Signed webhooks with HMAC-SHA-256, auto-pause after 10 consecutive failures, per-delivery log, and dedup id on every event. |
| Fingerprinting (cross-platform) | Stable identifier across OS reinstalls, different on every platform (macOS, Windows, Linux, CI). Handle CI bypass so build pipelines do not consume activations. 2-4 days; edge cases surface in production. | SDK handles hashing. CI mode ships built-in. Works across macOS, Windows, Linux. |
| Audit log | Append-only event log, retention policy, export (CSV or JSON), search by license key or customer. Cascade delete on owner removal to stay GDPR-clean. 2-3 days. | Every activation, deactivation, revocation, and webhook delivery logged. Exportable. Cascade-deleted on account removal. |
| Offline grace period | SDK-side cache of last positive verdict, configurable TTL, hard block on authoritative negatives (revoked, expired). Documented Electron/desktop recipe. 1-2 days, hard to test offline scenarios in CI. | 72-hour default grace window, hard block on revocation and expiry. Documented Electron recipe. Configurable TTL. |
| Management UI (dashboard) | CRUD for products, licenses, activations. Search, filter, revoke button, audit log view. Auth-gated, role-based. Accessible confirm dialogs, no browser alert(). Realistically 5-10 days for a usable internal tool. | Full dashboard ships with Paperkey. License search, activation view, webhook config, audit log, one-click revoke. |
| SDK maintenance (multi-language) | TypeScript for your web app. Python if you have a CLI. Go if you have a backend client. Same HMAC verifier, cross-language test vector, changelog, semver, npm + PyPI + Packagist releases. Ongoing indefinitely. | TypeScript, Python, PHP SDKs under MIT. Published and maintained. Same surface, same HMAC verifier, cross-language test vector. |
-
Key generation, format, rotation
- Build it yourself
- Write a generator, decide on a prefix scheme, handle rotation without invalidating live keys. Add a CSPRNG-backed format, store hashes (never plaintexts). Build a migration path for old key formats. 2-4 days.
- With Paperkey
- Prefix-namespaced keys out of the box. Hash storage enforced. Rotation is a single API call.
-
Rate limiting
- Build it yourself
- Per-IP limiter on validate, per-key limiter on activation, separate tighter limit on auth endpoints. Redis or in-memory depending on your infra. Handle burst, 429 responses, Retry-After headers. 1-2 days.
- With Paperkey
- Per-IP and per-key rate limits ship by default. Auth endpoints have a separate stricter budget.
-
Activation edge cases (machine swap, reinstall, seat limits)
- Build it yourself
- Track fingerprints per license, handle the "user reinstalled the OS" support ticket, decide how many machines per seat. Implement deactivation, cap enforcement, and the grace period for seat overflows. 3-6 days; ongoing support burden.
- With Paperkey
- Seat cap, per-machine fingerprint slots, deactivation endpoint, and grace period are all built in. Support tickets on edge cases go to us.
-
Webhook signing (HMAC, retries, dedup)
- Build it yourself
- HMAC-SHA-256 per delivery, idempotency key in the header, retry queue with backoff, auto-pause after N failures, per-delivery log, 5-second timeout. 2-3 days to get right; tricky to test.
- With Paperkey
- Signed webhooks with HMAC-SHA-256, auto-pause after 10 consecutive failures, per-delivery log, and dedup id on every event.
-
Fingerprinting (cross-platform)
- Build it yourself
- Stable identifier across OS reinstalls, different on every platform (macOS, Windows, Linux, CI). Handle CI bypass so build pipelines do not consume activations. 2-4 days; edge cases surface in production.
- With Paperkey
- SDK handles hashing. CI mode ships built-in. Works across macOS, Windows, Linux.
-
Audit log
- Build it yourself
- Append-only event log, retention policy, export (CSV or JSON), search by license key or customer. Cascade delete on owner removal to stay GDPR-clean. 2-3 days.
- With Paperkey
- Every activation, deactivation, revocation, and webhook delivery logged. Exportable. Cascade-deleted on account removal.
-
Offline grace period
- Build it yourself
- SDK-side cache of last positive verdict, configurable TTL, hard block on authoritative negatives (revoked, expired). Documented Electron/desktop recipe. 1-2 days, hard to test offline scenarios in CI.
- With Paperkey
- 72-hour default grace window, hard block on revocation and expiry. Documented Electron recipe. Configurable TTL.
-
Management UI (dashboard)
- Build it yourself
- CRUD for products, licenses, activations. Search, filter, revoke button, audit log view. Auth-gated, role-based. Accessible confirm dialogs, no browser alert(). Realistically 5-10 days for a usable internal tool.
- With Paperkey
- Full dashboard ships with Paperkey. License search, activation view, webhook config, audit log, one-click revoke.
-
SDK maintenance (multi-language)
- Build it yourself
- TypeScript for your web app. Python if you have a CLI. Go if you have a backend client. Same HMAC verifier, cross-language test vector, changelog, semver, npm + PyPI + Packagist releases. Ongoing indefinitely.
- With Paperkey
- TypeScript, Python, PHP SDKs under MIT. Published and maintained. Same surface, same HMAC verifier, cross-language test vector.
When rolling your own is fine
-
Single product, single platform: if you have one app and one validation endpoint, a simple server-side key check is a reasonable starting point.
-
No offline requirement: if your app is always online and you do not need a grace period, the licensing surface shrinks significantly.
-
No webhooks, no multi-seat: if you do not need to notify downstream systems and every license is single-seat, the activation edge cases disappear.
-
Prototype or internal tool: if the app is not customer-facing yet, the DIY version can buy you time before you invest in proper infrastructure.
Common questions
Is Paperkey comparable to a homemade licensing layer?
The managed surface is. Paperkey does what you would have to build: key generation, activation, validation, rate limiting, signed webhooks, audit log, dashboard. The SDK is MIT, the API is documented with OpenAPI 3.1, and the full stack is self-hostable. If you want to inspect it, the source is public.
What if I already started building my own?
You can migrate incrementally. One honest caveat: Paperkey issues the license keys, the create API does not take a key you supply. To preserve keys your users already hold, self-host and import them straight into your Postgres. On the managed service you issue fresh Paperkey keys and roll them out on the next update.
Can I self-host if I do not want a SaaS dependency?
Yes. The full monorepo is MIT. Single Docker compose, single Postgres, no phone-home. You get the same API and SDK as the managed version. See SELFHOST.md.
What does the homemade version get wrong most often?
The hard parts are the edge cases: machine swap on reinstall, CI pipelines consuming activations, webhook dedup after a transient failure, key rotation without invalidating live installs. Each one is individually solvable, but together they add up.
How long does integration take with Paperkey?
Three lines of SDK code to validate. The OpenAPI spec and llms-full.txt let Claude or Cursor read the API and write the integration for you. Most installs are under an hour.
Start with the off-the-shelf version.
Free tier (100 active licenses). No credit card. If you outgrow it or want full control, self-host the MIT monorepo.
Still evaluating?
Read the 5-minute quickstart. Or skip it: the SDK has decent defaults and the dashboard explains itself.