API v3 Reference
Current endpoints for workspace metadata, projects, statistics, and license-key management.
All authenticated endpoints need a developer API key of the workspace; one key reaches every project in it. Replace PROJECT_ID and the example keys with your values (the id of each project is in Dashboard → Developer API, or in the answer of GET /v3/projects). A license key is always 32 letters (A–Z and a–z); the examples use AbCdEfGhIjKlMnOpQrStUvWxYzAbCdEf.
Authorization: Bearer YOUR_DEVELOPER_API_KEY
Content-Type: application/jsonBodies are JSON, at most 16 KB. A field that breaks a rule answers 400 with the code INVALID_FIELD and a details list. The overview lists every limit and error code.
Public status
GET /v3/status
No authentication is required.
curl "https://luaward.com/v3/status"The response contains success, status, time (Unix seconds), and the API version.
Workspace metadata
GET /v3/keys/:key/details
Requires authentication. Returns the workspace's plan, the key's rate_limit, and projects: every live project with project_id, project_name, reset_hwid_allowed, reset_hwid_cooldown_days (how many days a player waits between resets of their own device; resets you make through the API ignore it), auto_delete_expired, allow_cloned_hwid, total_users, created_at, and its scripts (script_id, script_name, enabled, ffa). The :key segment is a placeholder that is never read. Write any word such as me, and never put your API key there, because addresses are logged.
GET /v3/keys/:key/stats
Requires authentication. Returns workspace-wide totals: total_projects, total_users, active_users, and total_executions. It is not a report for one license key. Also returns limits: for projects, scripts and keys, how many are in use (used) and what the plan allows (max). Add ?noUsers=true to leave out the user counts and the keys figure (quicker for a workspace with very many keys).
Projects
A project groups scripts and the license keys that open them. Making, renaming and deleting projects follows the same rules as the dashboard, including your plan's project limit.
GET /v3/projects
Returns projects: the same objects as in the details answer, oldest first.
GET /v3/projects/:id
Returns one project. A project that is not in your workspace, was deleted, or does not exist answers 404 with the code PROJECT_NOT_FOUND.
POST /v3/projects
{
"name": "My new project",
"reset_hwid_allowed": true,
"reset_hwid_cooldown_days": 7
}| Field | Rule |
|---|---|
| name | Required. 1 to 60 characters. |
| reset_hwid_allowed | Optional. Whether players may reset their own device. |
| reset_hwid_cooldown_days | Optional. 0 to 365. |
| auto_delete_expired | Optional. Delete expired keys automatically. |
| allow_cloned_hwid | Optional. Let one key run on several machines that share a device id. |
Success returns 201 and the new project. Webhooks and the "also accept keys from" list are set in the dashboard. Refusal: 403 PLAN_LIMIT when the workspace is at its project limit.
curl -X POST "https://luaward.com/v3/projects" \
-H "Authorization: Bearer YOUR_DEVELOPER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"My new project"}'PATCH /v3/projects/:id
Any of the fields above; at least one is required. Fields you leave out keep their value. Returns the updated project.
DELETE /v3/projects/:id
{ "confirm_name": "My new project" }Deleting needs the project's exact name in confirm_name, so a wrong id cannot remove the wrong project (400 CONFIRM_REQUIRED otherwise). As in the dashboard, the project and its scripts stop working at once and leave your lists. Success returns Project deleted successfully.
List license keys
GET /v3/projects/:id/users
Optional query parameters:
| Parameter | Meaning |
|---|---|
| page | Page number, 1 to 100000; defaults to 1. |
| limit | Results per page, 1 to 100; defaults to 50. |
| from | Start of a window of users, counted from the newest (0 or more). When given, it is used instead of page and limit. |
| until | End of that window: above from, by at most 100. Defaults to from + 50. |
| search | Up to 80 characters, matched against key, note, Discord id, and identifier. % and _ count as ordinary characters. |
| user_key | Exact license key filter (32 letters). |
| discord_id | Exact Discord id filter (15 to 22 digits). |
| identifier | Exact device identifier filter. |
| status | unused, active, reset, or banned. |
A value that breaks a rule returns 400; empty parameters are ignored. The response contains users, total, page, and limit. Each user has user_key, identifier, identifier_type, discord_id, note, auth_expire, key_days, status, banned, ban_reason, total_resets, total_executions, created_at, and last_executed_at. With a window, the response has from and until instead of page and limit.
Create a license key
POST /v3/projects/:id/users
{
"note": "Customer order 492",
"discord_id": "123456789012345678",
"key_days": 30
}| Field | Rule |
|---|---|
| user_key | Optional. Exactly 32 letters; Luaward makes one when you leave it out. |
| note | Up to 200 characters. |
| discord_id | 15 to 22 digits. |
| identifier | 8 to 200 characters; binds the key to a device in advance. |
| key_days | 1 to 36500. The key lasts this many days from its first use. |
| auth_expire | Unix seconds (up to the year 2100) when the key ends, or -1 for no end. When given, key_days is ignored. |
With neither key_days nor auth_expire the key never ends. Success returns user_key, key_days, auth_expire, and created_at; it is the only answer that shows a key Luaward made for you.
curl -X POST "https://luaward.com/v3/projects/PROJECT_ID/users" \
-H "Authorization: Bearer YOUR_DEVELOPER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"note":"Customer order 492","key_days":30}'Refusals: 403 PLAN_LIMIT when the workspace is at its key limit, 409 KEY_EXISTS when that key already exists.
Update a key
PATCH /v3/projects/:id/users
The body must include user_key, and at least one of note (text, or null to clear), discord_id (digits, or null to clear), and auth_expire (as above; it replaces key_days). identifier is accepted too: 8 to 200 characters to bind the key to a device, or null to take the binding off.
{
"user_key": "AbCdEfGhIjKlMnOpQrStUvWxYzAbCdEf",
"note": "Renewed",
"auth_expire": -1
}Delete a key
DELETE /v3/projects/:id/users
Pass user_key in a JSON body, or as a query parameter as Luarmor does (a body keeps the key out of the address). Success returns User deleted successfully. The deletion is recorded in the workspace audit log.
Reset a device binding
POST /v3/projects/:id/users/reset-hwid
{ "user_key": "AbCdEfGhIjKlMnOpQrStUvWxYzAbCdEf" }Success returns HWID reset successfully. The next valid run can bind the key to a device again. Like an owner's reset in the dashboard, it ignores the project's cooldown. Luarmor's spelling POST /v3/projects/:id/users/resethwid works too. force is accepted and changes nothing, because a reset here always skips the cooldown.
Link a Discord account
POST /v3/projects/:id/users/linkdiscord
{ "user_key": "AbCdEfGhIjKlMnOpQrStUvWxYzAbCdEf", "discord_id": "123456789012345678" }discord_id is 15 to 22 digits. A key that is already linked to a different account is left alone and answers 409 ALREADY_LINKED, unless you send "force": true. Linking the same account again succeeds. It does what discord_id in PATCH does, with that protection.
Ban and unban a key
POST /v3/projects/:id/users/ban
{ "user_key": "AbCdEfGhIjKlMnOpQrStUvWxYzAbCdEf", "reason": "Refunded order", "until": 1893456000 }reason is up to 200 characters. until is the Unix time the ban ends; leave it out for a permanent ban. A new ban replaces the end date of an earlier one. The response contains an unban_token (32 letters) that the loader's unban link accepts. To unban through the API, call POST /v3/projects/:id/users/unban with a body containing user_key; it clears the reason, the end date, and the token. Luarmor's route POST /v3/projects/:id/users/blacklist and its field names ban_reason and ban_expire (-1 means permanent) work as well; if both spellings are sent, ours win. Whoever holds the token can also lift the ban without an API key, with GET /v3/projects/:id/users/unban?unban_token=TOKEN: it works once, only inside that project, and is limited to 10 tries a minute per address.
Common error responses
Errors carry success: false, an error sentence, and a code. 400 is a body or field that breaks a rule, 401 an absent, wrong, or revoked key, 403 an address not on the list, a suspended account, or the plan's key or project limit, 404 a missing project or key, 409 a duplicate key, 413 a body over 16 KB, and 429 a rate limit. The overview has the full table.