Loading a protected script
This guide is for people running a script, not for the script owner. If you own the script, the dashboard covers upload, obfuscation and key issuance; start at the console.
Quick start
- 1.Get a key from the person or store that sold it to you. Keys look like
VIP-K7M2Q-9XTRB-4WPNZ-8HJCD. - 2.Sign in and claim it at My keys if the key requires a Discord account.
- 3.Put the key and your HWID into the loader call shown below and execute the script in your executor. The first successful call locks the key to that device.
Claim your key
Claiming links a key to your Discord identity. Sign in, open My keys, paste the key under Claim a key and submit. The key owner controls whether Discord is required; if it is not, claiming is optional but still useful — it is the only way an end user can reset their own HWID.
-- The console shows the exact snippet for each key.
-- GET /api/keys/<key-id>/loadstring returns { url, snippet, scriptName }The loader endpoint
The loader is a single HTTP GET. It answers with plain Luau source on success and with a Luau error call on failure — never an HTTP error for an auth problem, so your script fails with a readable message instead of a stack trace from the HTTP client.
GET /api/loader?key=<KEY>&hwid=<HWID>[&script=<slug-or-id>]
200 text/plain; charset=utf-8 → the script to loadstring
200 text/plain → error("incorrect key")script is optional when the key is scoped to a single script. If the key can access several scripts, pass the slug or id shown in the console.
Executor snippet
Replace the key and endpoint, then run this at the top of your script. Keep the HWID expression stable across sessions: an identifier that changes on every launch will look like a new device and trigger resets.
-- loader.lua — paste at the top of your scriptlocal KEY = "YOUR-KEY-HERE"local ENDPOINT = "https://your-deployment.vercel.app/api/loader" -- Use the stable device identifier your executor documents.-- RbxAnalyticsService:GetClientId() works on most modern executors.local HWID = tostring(game:GetService("RbxAnalyticsService"):GetClientId()) local ok, source = pcall(function() return game:HttpGet(ENDPOINT .. "?key=" .. KEY .. "&hwid=" .. HWID)end) if not ok or type(source) ~= "string" or source == "" then error("key system: could not reach the loader")end local chunk, compileError = loadstring(source)if not chunk then error("key system: " .. tostring(compileError))end chunk()If your executor supports one-line loader calls, this is the same thing without error handling:
loadstring(game:HttpGet(
"https://your-deployment.vercel.app/api/loader?key=YOUR-KEY&hwid=" .. HWID
))()HWID locking
A HWID key binds to the first device identifier it sees. Subsequent calls must come from the same identifier, which means a leaked key is useless on another machine. HWID values are stored with a fingerprint, not logged in full.
Agnostic keys skip the device check. They are useful for resellers and shared machines, but they cannot be HWID-locked later without issuing a new key — choose the type when you create the key.
The HWID string is opaque to the server. Use whatever your executor documents, as long as it is stable and does not contain personal data. Do not send a raw disk serial or email address.
Resets and cooldowns
When the hardware changes, the key owner (or a Discord-linked end user, if the key allows self-reset) can reset the binding. Resets are rate-limited by a per-key cooldown — commonly 24 hours — and each reset is logged with the old and new fingerprint.
- Cooldown starts when the reset succeeds, not when the key was issued.
- The console disables the reset button while the cooldown is active and shows the remaining time; the API rejects the call with the same rule.
- Resets do not change the key value. Do not resend a key to a user for a reset.
Discord binding
A key flagged discord_required only works for the Discord account that claimed it. This is the strongest protection against resale: the buyer links their account once and the key follows the identity, not the machine.
The key owner can unlink an identity at any time, which immediately frees the key for a new claim. Every link and unlink is written to the usage log.
Delivery tokens
When the double-check bootstrap is enabled, the delivered source contains a short-lived token signed by the server and bound to the key, script and HWID. The bootstrap verifies that token before handing control to the script, which makes a copied response body useless a few seconds later and useless on another device.
- Tokens are single-use and expire in under two minutes by default.
- Do not cache or re-host the delivered source; it will fail the token check.
- If a delivery fails the check, re-run the loader call to get a fresh token.
Troubleshooting
| Message | What it means | Fix |
|---|---|---|
| incorrect key | The loader rejected the request. Every auth failure returns this same message on purpose, so it cannot tell you whether the key was missing, revoked, expired or bound to another device. | Copy the key again from My keys, confirm it is not revoked or expired, and check the console log for the exact reason recorded against the key prefix. |
| HWID does not match | The key is already locked to another device identifier. | Use the device that originally bound it. If the hardware changed, reset the HWID from My keys — within the cooldown window this API will refuse. |
| HWID is missing | The request did not send a `hwid` parameter, or it was empty. | Pass `hwid` on every request. A HWID key cannot bind without one; an agnostic key still needs the parameter. |
| rate limited | Too many loader calls from one IP or one key inside the minute window. | Cache the delivered source for the session instead of re-fetching on every frame, and back off when the loader answers slowly. |
| script is disabled | The script's status is `disabled` or `draft` in the console. | Ask the script owner to set the status to Active. Draft scripts are never delivered. |
| Discord account required | The key is flagged `discord_required` and is not linked to a Discord identity yet. | Sign in, open My keys and claim the key — claiming binds your Discord identity. Then retry the loader. |
The console records the real reason against the key prefix — “incorrect key” is only what the client is told. If a user reports a failure, search the logs by key prefix rather than guessing.
Limits
- Loader calls are limited per IP and per key per minute; repeated hits are refused temporarily.
- Keys can expire, be revoked, or carry an execution ceiling. All three fail closed.
- Scripts in draft never deliver; disabled scripts stop immediately.
- Source size is capped server-side. If your script is large, split it rather than raising the cap on the client.
Ready to try it?
Claim a key, then open My keys for its exact snippet.