---
url: https://docs.sunlicense.com/how-to/velocity-plugin.md
description: >-
  How to add license keys to a Velocity (Minecraft proxy) plugin - check the
  buyer's key with the SunLicense Java SDK on ProxyInitializeEvent through
  Velocity's scheduler, stop on a rejection, keep running offline, and sell it
  on BuiltByBit or Voxel Shop.
---

# How to add license keys to a Velocity plugin

**Short answer:** add the SunLicense Java SDK (shaded and relocated), read the buyer's key from your plugin's data
directory, check it on `ProxyInitializeEvent` through Velocity's scheduler, and switch your features off when
SunLicense says no. A network error is not a no: keep running and check again later.

```java
// build.gradle.kts: implementation("com.sunlicense:sunlicense:0.0.1"), shaded and relocated
private final SunLicense client = new SunLicense.Builder()
        .baseUrl("https://api.sunlicense.com").token("slk_…").build();   // API key from your build, never git
private volatile boolean licensed;

@Subscribe
public void onProxyInitialize(ProxyInitializeEvent event) {
    String key = loadConfig().getProperty("license-key", "");   // plugins/myplugin/config.properties
    proxy.getScheduler().buildTask(this, () -> {
        try {
            SunLicense.Result r = client.validate(key, Map.of("host", machineId()));
            licensed = r.getStatus() != 400;   // only a 400 is SunLicense saying no
            if (!licensed) logger.error("MyPlugin license rejected: {}", r.getBody());
        } catch (SunLicense.SunLicenseException e) {
            licensed = true;   // unreachable: keep running, check again later
        }
    }).schedule();
}
```

Velocity runs scheduler tasks on its own thread pool, so the network call never holds up the proxy. Your listeners
and commands start with `if (!licensed) return;`.

**Start from the template instead:** [example-velocity-plugin](https://github.com/sunlicense-com/example-velocity-plugin)
(Velocity 3.5 and 4.x, Java 21) has this plus a stable machine id, masked keys, re-checks every 6 hours, a signed
offline license fallback, BuiltByBit placeholders, a sealed core, `/myplugin` status and recheck commands, tests and
CI. [All templates](/guide/templates).

**Or let your AI agent do it:** paste the [setup prompt](https://sunlicense.com/prompt) into your coding agent.

Free plan: 3 products, 100 licenses, no credit card. [Create a free account](https://sunlicense.com/start?ref=docs-howto-velocity).

## Step by step

1. **In the dashboard:** a product, a policy (a machine is a proxy here, so *1 machine* fits a single network) and an
   **API key**, which can only validate licenses.
2. **Add the SDK** and relocate it with Shadow (`relocate("com.sunlicense", "com.example.myplugin.libs.sunlicense")`)
   so plugins with different SDK versions don't clash.
3. **Keep the API key out of git:** `~/.gradle/gradle.properties`, expanded into a resource at build time.
4. **The buyer's key:** `config.properties` in the `@DataDirectory` folder, or a `%%__SUNLICENSE__%%` placeholder that
   [BuiltByBit](/integrations/builtbybit) and [Voxel Shop](/integrations/voxel-shop) fill in on download.
5. **Machine id** as `host`: a hash of OS, architecture and host name (snippet in the [Paper guide](/how-to/paper-plugin#step-by-step)).
6. **Results:** 200 runs your features, 400 stops them with the [reason](/guide/concepts#validation-result-codes)
   (keys masked in logs), anything else keeps running and retries in about 10 minutes or uses an
   [offline license](/guide/offline-licenses). Re-check with `.repeat(6, TimeUnit.HOURS)` so a revoked key reaches
   running proxies.

## Selling it

One proxy usually fronts several backend servers. License the proxy plugin per proxy (the machine limit counts
proxies), and if you also sell a Paper companion plugin, give it its own product or policy so each counts its own
machines. Stores: [BuiltByBit](/integrations/builtbybit), [Voxel Shop](/integrations/voxel-shop),
[Tebex](/integrations/tebex), [SpigotMC](/integrations/spigotmc) and the [others](/integrations/).

## Going further

* [Protection](/guide/protection) and [obfuscation](/guide/obfuscation) for the jar you sell.
* [Paper](/how-to/paper-plugin) and [Fabric](/how-to/fabric-mod) versions of this guide.
  More on [licensing Minecraft plugins](https://sunlicense.com/for/minecraft-plugins/).
