Licensing Integration
Protect your plugins with built-in license key management. Buyers receive a unique key on purchase; your plugin calls our API to activate and validate it.
Overview
When you enable licensing on a product, each buyer automatically receives a unique license key formatted as PULSE-XXXX-XXXX-XXXX-XXXX after purchase. Your plugin uses this key to:
- Activate — register a server with the key on first start
- Heartbeat — periodically confirm the license is still valid (every 30 min recommended)
- Validate — lightweight status check without updating the heartbeat
- Deactivate — free a slot when moving to a new server
After a successful activation, the API returns a signed JWT token your plugin can cache locally. If the server loses internet access, the plugin keeps working for the offline grace period you configure (default 24 hours).
License Types
No License
No key is issued. The plugin can be downloaded and used freely with no enforcement.
User Bound
One key per buyer. The key can be activated on any number of servers but is tied to the purchasing account.
Single Server
One activation allowed per key. Ideal for plugins sold per-server.
Multi Server
Set a maximum activation count (e.g. 3 servers per key). Buyers can deactivate and reuse slots.
Floating
Like Multi Server but activations expire after an inactivity period if the heartbeat is not called.
Quick Start — Java (Minecraft)
Add a license-key field to your config.yml, then call the activation endpoint in onEnable():
import java.net.URI;
import java.net.http.*;
import com.google.gson.*;
public class MyPlugin extends JavaPlugin {
private String licenseToken = null;
@Override
public void onEnable() {
String licenseKey = getConfig().getString("license-key", "");
String serverId = getServer().getName() + "-" + getServerId();
if (!activateLicense(licenseKey, serverId)) {
getLogger().severe("License activation failed! Disabling plugin.");
getServer().getPluginManager().disablePlugin(this);
return;
}
// Schedule heartbeat every 30 minutes
getServer().getScheduler().runTaskTimerAsynchronously(
this, () -> heartbeat(licenseKey, serverId), 36000L, 36000L
);
}
private boolean activateLicense(String key, String serverId) {
try {
String body = new Gson().toJson(Map.of(
"key", key,
"server_id", serverId,
"server_label", getServer().getMotd()
));
HttpResponse<String> res = HttpClient.newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("https://pulseplugin.net/api/v1/license/activate"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build(),
HttpResponse.BodyHandlers.ofString()
);
if (res.statusCode() == 200) {
JsonObject json = JsonParser.parseString(res.body()).getAsJsonObject();
this.licenseToken = json.get("token").getAsString();
return true;
}
return false;
} catch (Exception e) {
return false; // Allow offline grace period
}
}
private void heartbeat(String key, String serverId) {
try {
String body = new Gson().toJson(Map.of("key", key, "server_id", serverId));
HttpClient.newHttpClient().send(
HttpRequest.newBuilder()
.uri(URI.create("https://pulseplugin.net/api/v1/license/heartbeat"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build(),
HttpResponse.BodyHandlers.ofString()
);
} catch (Exception ignored) {}
}
}Best Practices
Cache the JWT token
Store the token from /activate and /heartbeat to disk. If the internet is unreachable, verify the cached token locally using the JWT expiry. The token TTL (48h) plus the offline grace period (24h) gives at least 3 days of offline operation.
Don't hard-stop on network errors
Only disable the plugin on explicit errors like license_revoked or invalid_key. Network timeouts should fall through to the offline grace period — buyers' servers should not go down because of a CDN hiccup.
Stable server identifiers
Use a UUID generated once and persisted on first run (e.g. in plugins/YourPlugin/server-id.txt). Avoid using IP addresses — they change when buyers migrate hosts and consume new activation slots.
Manual / Complimentary Licenses
As a seller you can issue a license key to any buyer by email from the Licenses tab in your seller dashboard. This is useful for:
- Giving complimentary access to testers or partners
- Replacing a lost key for an existing buyer
- Providing review copies
Manually issued licenses show a Complimentarybadge in the buyer's dashboard.
Full API Reference
The plugin-side API (activate, heartbeat, validate, deactivate endpoints) is documented in detail under API Reference → Licensing.