Migration guide
Move from Keygen to Paperkey.
You export your existing licenses from Keygen, transform the JSON to the Paperkey shape, POST them in. The SDK call site in your shipped app stays the same. The dashboard, the webhooks, and the audit log come up populated on the first reload.
A one-off script against your own instance, sized by your license count
Concept mapping
Most concepts map one-to-one. The names differ in three places (Account, Policy, Token).
-
- Keygen
- Account
- Paperkey
- Workspace (account)
- Note
- Top-level isolation. One per company.
-
- Keygen
- Product
- Paperkey
- Product
- Note
- Same idea. Carries config (cap, fingerprint policy).
-
- Keygen
- Policy
- Paperkey
- Product config
- Note
- Inlined into the product. Per-license overrides on the License.
-
- Keygen
- License
- Paperkey
- License
- Note
- Same. Arbitrary key formats accepted on import.
-
- Keygen
- Machine
- Paperkey
- Activation
- Note
- Same. Hashed fingerprint, slot of cap.
-
- Keygen
- Token (license token)
- Paperkey
- Validation token
- Note
- JWT issued by validate. Compatible drop-in shape.
-
- Keygen
- Webhook
- Paperkey
- Webhook event
- Note
- HMAC-SHA-256, hex signature, 5s timeout.
-
- Keygen
- Entitlement
- Paperkey
- License metadata
- Note
- Stored as JSON on the license. Read by the SDK.
Four steps
1. Export from Keygen
Use the Keygen API to dump every license into a single JSON file. Replace <account-id> and <keygen-api-token> with your values.
curl -X GET 'https://api.keygen.sh/v1/accounts/<account-id>/licenses' \
-H 'Authorization: Bearer <keygen-api-token>' \
-H 'Accept: application/vnd.api+json' \
> keygen-licenses.json2. Transform to the Paperkey shape
A small Node one-liner. Reads keygen-licenses.json, projects every license into the Paperkey input format, writes paperkey-licenses.json. No external dependencies.
node -e '
const data = JSON.parse(require("fs").readFileSync("keygen-licenses.json", "utf8"));
const out = data.data.map(l => ({
key: l.attributes.key,
customerEmail: l.relationships?.user?.data?.id ?? null,
expiresAt: l.attributes.expiry,
activationCap: l.attributes.maxMachines ?? 1,
metadata: l.attributes.metadata ?? {},
}));
require("fs").writeFileSync(
"paperkey-licenses.json",
JSON.stringify(out, null, 2)
);
'3. Import into Paperkey
Paperkey mints license keys server-side. To keep the keys your customers already hold, import the exported rows straight into the licenses table of your self-hosted Postgres. Creating them through POST /licenses issues new keys.
jq -c '.[]' paperkey-licenses.json | while read -r row; do
curl -X POST https://api.example.com/v1/licenses \
-H "Authorization: Bearer pk_<your-api-key>" \
-H 'Content-Type: application/json' \
-d "$row"
done4. Update the SDK config
In your shipped app, set the SDK baseUrl to your self-hosted instance. The SDK call site stays the same. Customers keep validating with their existing keys.
import { Paperkey } from '@paperkeyhq/sdk';
const pk = new Paperkey({
apiUrl: 'https://api.example.com',
productId: 'prod_<your-product-id>',
publicKey: '<your-paperkey-public-verify-key>',
});
// Same call site as before. The SDK handles cache + offline grace.
const verdict = await pk.validate(licenseKey);Known limitations
Honest list. We tell you upfront so you do not discover them in production.
- Machine fingerprints are regenerated on first activation against Paperkey. Existing Keygen machine slots are translated to "available capacity" on the license, not pre-bound to specific machines.
- Custom Keygen webhooks are not auto-replayed. Re-subscribe in the Paperkey dashboard with the same target URLs; we will resend on every state change going forward.
- Complex entitlements (per-feature flags) come over as JSON metadata on the license. The SDK exposes them with `license.metadata.<key>`. Refactor your feature gates accordingly.
- License analytics history (charts, time series) does not migrate. The Paperkey audit log starts on the day of import.
Need a hand?
If you have more than 10k licenses, complex entitlements, or just want eyes on the migration, write to us with your Keygen account size and a contact time. We do walkthroughs in 30 minutes against your real data, free.
Email hello@paperkey.dev