Desktop-first · no API key in your binary

Licensing built for
desktop software

Activation, trials, subscriptions, perpetual licenses, payments, auto-updates and a customer portal — in one platform. Your app ships a license key, verifies offline, and your customers manage their own devices and invoices.

No credit card Offline Ed25519 Self-hosting available
activate.js
// 客户端只保存授权码与公钥
const res = await fetch('https://keygate.unionuser.com/api/v1/license/activate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    license_key: userKey,        // WB-XXXX-XXXX
    identifier: deviceId,        // sha256(machine-id)
    identifier_type: 'device'
  })
});

const { token } = await res.json();
await store.save(token);       // verify offline with Ed25519
LicenseActive
WB-8F2K-••••-M4Q9
PlanPro · Yearly
Devices
Offline until+7 days
Ed25519 signed licenses Atomic activation slots Stripe subscriptions & perpetual Sparkle · Velopack · Tauri Private deployment
Why UnionUser

Licensing as a product, not a pile of glue code

Most desktop apps eventually hand-roll a license server, payment hooks and an update feed. UnionUser turns that pile of glue into a product.

Your binary ships no secret

SDK endpoints take the customer’s own license key. No API secret inside your installer, so a leaked build leaks nothing extra.

How offline verification works

Customers serve themselves

Device moves, seat changes, invoices and maintenance renewals all live in the customer portal — not in your support inbox.

Customer portal

Your data stays yours

Use the managed SaaS, or buy a commercial self-hosted license. Go + PostgreSQL, and it runs without Redis.

Self-hosting
One dashboard

Licenses, devices, payments and releases in one place

From the first trial key to the 10,000th activated device, the dashboard answers: who, until when, on which device, paid how much, and which release they should get.

  • Filter licenses by product, plan and status; issue and revoke in bulk
  • Device activation records and releases with atomic slot accounting
  • Stripe payments, refunds, billing portal and expiry reminders
  • Sparkle / Velopack / Tauri release feeds with per-release signatures
UnionUser · Dashboard Live
UnionUser licensing dashboard screenshot
Capabilities

Everything a desktop license needs

Every capability maps to a real API and a real screen in the dashboard.

Licensing & activation

Subscriptions, perpetual, trials and floating licenses across the full lifecycle.

Learn more

Offline Ed25519 verification

Pin the public key, keep the private key on the server. Check-in interval is separate from licence expiry.

Learn more

Trials & self-signup

Email-OTP signup issues a trial instantly, one per address, daily capped, with fallback plans.

Learn more

Payments & subscriptions

Stripe Checkout with webhook, success-page and scheduled reconciliation safeguards.

Learn more

Seats & entitlements

Owner and member keys, seat pause, boolean, numeric and quota entitlements.

Learn more

Update distribution

One release feed for Sparkle, Velopack and Tauri, with atomic publishing and yank.

Learn more

Usage & quotas

Atomic quotas on hourly, daily, monthly or yearly windows with threshold webhooks.

Learn more

Admin & customer portal

Products, plans, customers, API keys, audit, team and branding; customers self-serve.

Learn more
Five steps

From sign-up to the first activated device

You do not need the whole manual. Five steps get you a working license path.

1

Create workspace

Sign in with an email code. Takes 30 seconds.

2

Add product & plan

Set device limits, grace period and entitlements.

3

Issue licenses

Issue keys manually, or let Stripe issue them.

4

Activate in the app

Call activate and store the signed token.

5

Ship & observe

Verify offline; watch devices, payments and releases.

Integration guides

Five languages, working today

Every guide covers activate → store → verify on startup → deactivate. The client stores a license key and a public key, never an API secret.

JavaJavaScriptPythonRustPHP
verify.jsEd25519
import { verify } from 'node:crypto';

const [body, sig] = token.split('.');
const ok = verify(
  null,
  Buffer.from(body, 'ascii'),
  publicKey,              // pinned SPKI
  Buffer.from(sig, 'base64url')
);
if (!ok) throw new Error('bad signature');
Pricing

Priced against real usage

Developer is free forever. Pro comes with a 31-day, full-feature trial — no credit card.

Developer

Personal projects and prototypes

$0
1 product(s) · 100 active licenses

Business

Multiple products and teams

$99/mo
10 product(s) · 10,000 active licenses

Enterprise

Large teams, self-hosting and white-label

$399/mo
Unlimited product(s) · Unlimited active licenses

Billed on active licenses · annual saves two months · self-hosted licenses quoted separately. See full pricing →

FAQ

What engineers ask first

Does my app need an API key baked in?

No. Public license endpoints accept the customer’s license key as the credential. Your app only pins the public key used to verify signatures.

Does licensing work offline?

Yes. The license token is Ed25519-signed and the client verifies signature, device binding and expiry offline. It checks in again when the token expires.

How many devices per license?

The plan defines it; 3 is the recommended default. Slots are decremented atomically in the database, so retries do not double-count, and customers can release devices in the portal.

Which payment methods are supported?

Stripe is built in: subscriptions, perpetual licenses, trials, refunds, billing portal and expiry reminders. You can also issue keys manually after an offline sale.

Can we self-host?

Yes. A commercial self-hosted license lets you run the Go service and PostgreSQL with Docker Compose. The source is not public.

Must we use UnionUser for updates?

No. Keep your existing OSS/CDN if you prefer. Using the UnionUser feed adds license-gated downloads, yank and per-product signatures.

Wire up licensing today

Start a 31-day trial. Verify offline in the client, revoke from the dashboard anytime.