---
url: https://docs.sunlicense.com/guide/sdks.md
---
# SDKs

Official, open-source clients live at [github.com/sunlicense-com](https://github.com/sunlicense-com). They all use the same two settings:

| Setting | Value |
|---|---|
| Base URL | `https://api.sunlicense.com` |
| Token | an API key from **Dashboard → API keys** (`slk_…`) |

The examples read the API key from the `SUNLICENSE_API_KEY` environment variable (or, in FiveM, the `sunlicense_api_key` convar). Keep it apart from `SUNLICENSE_TOKEN`, which holds a [personal access token](/cli/) (`slp_…`) for the CLI and AI assistants: that one can manage your organization and never belongs in an app.

Every SDK calls `POST /api/v2/license/validate`. HTTP **200** means valid; **400** means rejected, and the body's `code` says why ([result codes](/guide/concepts#validation-result-codes)). Pass a stable machine id as `host` so machine limits work.

::: code-group

```java [Java]
// implementation 'com.sunlicense:sunlicense:0.0.1'
SunLicense client = new SunLicense.Builder()
        .baseUrl("https://api.sunlicense.com")
        .token(System.getenv("SUNLICENSE_API_KEY"))
        .build();

SunLicense.Result result = client.validate(licenseKey, Map.of("host", machineId));
if (!result.isValid()) { /* result.getBody() has the code */ }
```

```js [JavaScript]
// npm install sunlicense
import { SunLicense } from "sunlicense";

const client = new SunLicense({ baseUrl: "https://api.sunlicense.com", token: process.env.SUNLICENSE_API_KEY });
const result = await client.validate(licenseKey, { host: machineId });
```

```python [Python]
# pip install sunlicense
import os
import platform

from sunlicense import SunLicense

client = SunLicense(base_url="https://api.sunlicense.com", token=os.environ["SUNLICENSE_API_KEY"])
result = client.validate(license_key, host=platform.node())
```

```csharp [.NET]
// dotnet add package SunLicense
using var client = new SunLicenseClient("https://api.sunlicense.com",
    token: Environment.GetEnvironmentVariable("SUNLICENSE_API_KEY"));
var result = await client.ValidateAsync(licenseKey, new Dictionary<string, string> { ["host"] = machineId });
```

```php [PHP]
// composer require sunlicense/sunlicense
$client = new SunLicenseClient('https://api.sunlicense.com', token: getenv('SUNLICENSE_API_KEY'));
$result = $client->validate($licenseKey, ['host' => $machineId]);
```

```lua [Lua]
-- luarocks install sunlicense (or drop sunlicense.lua into your FiveM/GMod resource)
local SunLicense = require("sunlicense")
local client = SunLicense.new({ baseUrl = "https://api.sunlicense.com", token = GetConvar("sunlicense_api_key", "") })
client:validate(licenseKey, { host = GetConvar("sv_hostname", "") }, function(ok, status, body) end)
```

:::

The Rust client (`cargo add sunlicense`) currently provides configuration only; validation is coming.

Writing a Minecraft plugin or mod, a FiveM resource or a Discord bot? Start from a [template](/guide/templates): the SDK, store placeholders, messages and an offline fallback, ready to build.

Using an AI coding assistant? [Use SunLicense with your AI assistant](/guide/ai-assistants) has a ready prompt for each language and the docs in a format assistants read well.

## Choosing a machine id

Use something stable across reboots and updates: a hash of hardware identifiers, or an id you generate once and store. Don't use the IP address. The Java CLI's `fingerprint` command shows one approach.

## Handling errors

| HTTP | Meaning | Recommended behaviour |
|---|---|---|
| 200 | Valid | Continue |
| 400 | Rejected (see `code`) | Block or prompt, depending on the code |
| 401 | Missing or wrong API key | A configuration bug in your app |
| 429 | Rate limited | Retry later |
| 5xx / network error | SunLicense is unreachable | Fall back to the [offline license](/guide/offline-licenses) |
