The server that vouches for your app's purchases and license keys.
Keywarden turns App Store and Google Play purchases and license keys into one signed entitlement bundle your app verifies offline — ECDSA P-256, no header, no server round trip after the first sync, and never a lockout on a network hiccup. Nothing to run yourself: add the SDK, ship.
Invite-only while we scale. Free for everyone in early access.
// request { "store": "play", "productId": "pro", "purchaseToken": "…", "device": { "installId": "…" } } // response — signed, verifiable offline { "ok": true, "purchase": { "state": "active" }, "bundle": "eyJ2IjoyLCJhcHAiOi….MEUCIQ…" }
Four calls, no infrastructure to run.
Create an app
Sign in at the dashboard, create an app, get a public key (pk_live_…) and a signing key pair.
Embed & pin
Ship the public key in your binary; pin the signing key's SPKI so bundles verify fully offline.
Sync & verify
Call /v1/devices/sync or /v1/store/verify; check the signed bundle on device.
Issue licenses
Selling outside the store too? Issue KW-… keys from the dashboard or the CLI.
Everything a paid app needs, one API.
App Store & Google Play verification
Receipts are checked against the store and recorded. StoreKit 2 transactions are verified against Apple Root CA G3 offline, then confirmed with the App Store Server API; refunds arrive as signed server notifications. The voided-purchases list is polled in the background so refunds drop on the next check — and if that list is ever unreachable, the health endpoint says so instead of silently letting a refund through.
License keys with floating seats
KW-XXXX-XXXX-XXXX-XXXX keys, issued from the dashboard or the CLI. Seats can be fixed or floating — a floating seat frees itself after a heartbeat TTL, or the moment a device deactivates.
Signed entitlement bundles, verified offline
The server never says "you own it" — it signs it, ECDSA P-256, no header. The app verifies the bundle on device, so editing a preferences file on a rooted phone buys nothing.
Devices & GDPR erase
Every install is tracked (platform, last seen, active entitlements) from the dashboard. A single erase call removes a device and everything tied to it, in one transaction.
Metered features, trials & gift thresholds
"Try it 3 times" counters live on the server, not in a local file. Optional purchases add up and unlock a tier once a threshold is reached; amounts freeze at purchase time, so a later price change never rewrites history.
A dashboard for all of it
Overview, devices, stores, license keys, catalog, signing keys, audit log — all at app.keywarden.dev, sign-in by magic link.
Management API, fully documented
Organizations, apps, entitlements, licenses, devices, audit log — behind sk_live_… keys, with a published OpenAPI schema.
kw — a real CLI
Create apps, issue and revoke license keys, list devices, run a full self-test or inspect a bundle — without leaving the terminal.
Signing-key rotation, safely
Rotate a signing key and the old one stays valid through the overlap window. A key with usage in the last 30 days can't be retired — no silently bricked clients.
Configure once. Ask anywhere.
Keywarden.configure(
Config.Builder(this)
.apiKey(BuildConfig.KEYWARDEN_PK)
.publicKey("k1", SPKI_B64) // pinned; verifies offline
.appSlug("my-app")
.build()
)
Keywarden.get().sync(object : SyncCallback {
override fun onResult(verdict: Verdict, error: KeywardenException?) { refreshUi() }
})
if (Keywarden.get().has("pro")) unlockPro() // local, never blocks
let client = Keywarden.configure(try Configuration(
apiKey: "pk_live_…",
baseURL: URL(string: "https://api.keywarden.dev")!,
publicKeys: ["k1": SPKI_B64], // pinned; verifies offline
appSlug: "my-app"
))
// StoreKit 2: launch scan + Transaction.updates, verified server-side
StoreKitSync(client: client, source: StoreKitTransactionSource()).start()
if client.has("pro") { unlockPro() } // local, never blocks
Ask for an invite.
Keywarden runs on our own infrastructure and every account costs us something, so we are letting people in a handful at a time. Leave your e-mail and we will send you a sign-in link when a slot opens.
Self-hosting instead? The server ships as a Docker image — see the docs. No invite needed.
Free while we are in early access.
Everyone invited today uses Keywarden for free, with no card and no expiry date on what you have already shipped. The plans below are what we intend to charge once billing exists — they are published early so nothing about the price is a surprise later.
Everything below, while we are invite-only. Store verification, signed entitlements, license keys, trial counters, devices, dashboard and CLI.
Request an invite →1 app · 100 users. Store verification, signed entitlements, trial counters, dashboard.
When billing ships10 apps · 50,000 users. License keys and device activation, webhooks, e-mail support.
When billing ships25 apps · 200,000 users. Payment-provider integrations, 3 team members, priority support.
When billing shipsBilling, payment-provider webhooks (Paddle, Lemon Squeezy) and plan quotas Not built yet — no card is collected anywhere on this site today.