How to add license keys to a JDA bot
Short answer: add the SunLicense Java SDK, read the buyer's key from an environment variable or config.properties, check it before JDABuilder...build(), and exit when SunLicense says no. A network error is not a no: start anyway and check again later.
// build.gradle.kts: implementation("com.sunlicense:sunlicense:0.0.1") next to JDA, in one shadow jar
public static void main(String[] args) {
SunLicense client = new SunLicense.Builder()
.baseUrl("https://api.sunlicense.com").token(API_KEY).build(); // API key from your build, never git
try {
SunLicense.Result r = client.validate(System.getenv("LICENSE_KEY"), Map.of("host", machineId()));
if (r.getStatus() == 400) { // EXPIRED, REVOKED, TOO_MANY_MACHINES…
System.err.println("License rejected: " + r.getBody());
System.exit(1);
}
} catch (SunLicense.SunLicenseException e) {
System.err.println("SunLicense unreachable, starting anyway: " + e.getMessage());
}
JDA jda = JDABuilder.createLight(System.getenv("DISCORD_TOKEN")).build();
}Start from the template instead: example-discord-bot-jda (Java 21, JDA 6) has this plus a stable machine id, masked keys, re-checks every 6 hours, a signed offline license fallback, a sealed core package, a /license command, tests and CI.
Or let your AI agent do it: paste the setup prompt into your coding agent.
Free plan: 3 products, 100 licenses, no credit card. Create a free account.
Step by step
- In the dashboard: a product, a policy (1 machine = one running copy per license) and an API key, which can only validate licenses.
- One runnable jar. Add the SDK with
implementationand build with Shadow; relocating it isn't needed in a bot that runs alone, but does no harm. - Keep the API key out of git: put it in
~/.gradle/gradle.propertiesand expand it into a resource at build time. The buyer'sDISCORD_TOKENandLICENSE_KEYcome from their environment orconfig.properties. - Machine id as
host: a hash of OS, architecture and host name (snippet in the Paper guide). In Docker, set a fixedhostname:or the container id changes on every restart. - Results: 200 builds JDA, 400 exits with the reason (keys masked in logs), anything else starts and retries in about 10 minutes, or uses an offline license.
- Re-check every few hours on a
ScheduledExecutorService; on a 400 calljda.shutdown()and exit.
Selling it
Tebex, Gumroad, Lemon Squeezy, Stripe, BuiltByBit and the other stores issue a key per purchase and revoke it on a refund. A jar downloaded from BuiltByBit or Voxel Shop can carry the key through a %%__SUNLICENSE__%% placeholder.
Going further
- Protection and obfuscation for the jar.
- discord.js and discord.py versions of this guide. More on licensing Discord bots.
