Skip to main content
NMKey is NMCrate’s own licensing backend for paid plugins. Unlike third-party license services, the entire validation pipeline runs on NMCrate itself — there is nothing external to spoof, throttle, or take offline.

How it protects your plugin

  1. A buyer completes checkout on NMCrate.
  2. NMCrate mints a unique NMK-… key bound to one live server at a time.
  3. The download bakes the buyer’s key into their plugin.jar as an embedded nmkey.txt — there is nothing for buyers to copy or configure.
  4. On boot, your plugin validates the key via the NMKey library (asynchronously), which verifies the Ed25519-signed response.
  5. The first server claims the license seat; any second server is rejected with max_servers. A leaked key simply refuses to boot anywhere else.
Responses are cryptographically signed, so even if an attacker reroutes the API to a fake server that always answers “valid”, the library verifies the signature against NMCrate’s public key and rejects the forgery.

The NMKey library

The officially endorsed client is an ultra-lightweight Kotlin/JVM library (GuavaDealer/NMKey, Apache 2.0):
  • No networking bloat — no Ktor, no coroutine dispatchers; just the native Java 17 HttpClient and the Bukkit API, with kotlinx.serialization for reflection-free JSON.
  • Dynamic fingerprinting — identifies the server with in-memory JVM heuristics (processors, OS arch, server port) to prevent seat spoofing in containerized environments.
  • Offline grace period — a 256-bit AES-GCM encrypted cache keyed to the server’s fingerprint lets valid buyers survive API outages for up to 48 hours.
  • Self-Cleaning architecture — hooks Bukkit’s PluginDisableEvent to automatically release the license seat and destroy HTTP threads on shutdown or /reload; no manual cleanup needed.

Requirements

Java17+
Paper API1.17+
Kotlin2.4+ (stdlib + serialization, shaded into your jar)

Enabling NMKey for a product

In your studio dashboard, open Licensing → Add license, pick the plugin, and choose NMKey Plugin Safe. You’ll get an 8-character plugin id — that’s the PLUGIN_ID your code passes to the library. Default policy (servers per key, expiration) is configurable per product, and individual keys can be revoked or adjusted from the same tab. Not on the JVM? The raw HTTP endpoints are public — see the NMKey HTTP API.