KeyForgeDocs
Sign inGet started

Creator & Scale

Custom key UI

Your Roblox UI. KeyForge still checks the key and delivers the script.

Setup

1

Turn on custom mode

Edit a keyed script, open In-game UI, pick Custom Lua GUI.

2

Copy the snippet

The dashboard gives you IDs and a signed integration token for that script.

3

Hook your buttons

Call getKeyUrl, verify, and loadScript from your own buttons and TextBox.

API

Three calls

client:getKeyUrl()

Returns the linked key-page URL, or nil if none is linked.

client:verify(key)

Solves a one-time challenge, checks the key on the server, then stores a short-lived access token.

client:loadScript()

Runs delivery, including executor fingerprint and HWID. The access token is one-shot.

Do not put database credentials, API secrets, raw source, or key-check rules in your Lua GUI. The integration token names a script. It is not a server secret. A dumped script can still be read. KeyForge can mark a dump and cut off later loads. It cannot erase a copy someone already has.

Starter snippet
local sdkUrl = "https://test.keyforge.win/sdk/client.lua"
local downloaded, sdkSource = pcall(function()
    return game:HttpGet(sdkUrl, true)
end)
assert(downloaded and type(sdkSource) == "string",
    "[KeyForge] Could not download the SDK: " .. tostring(sdkSource))

local compiler = loadstring or load
assert(type(compiler) == "function",
    "[KeyForge] This executor does not provide loadstring.")

local compiled, sdkChunk, compileError = pcall(compiler, sdkSource)
assert(compiled and type(sdkChunk) == "function",
    "[KeyForge] SDK response was not valid Lua. The host may be blocking executor requests: "
        .. tostring(compiled and compileError or sdkChunk))

local initialized, KeyForge = pcall(sdkChunk)
assert(initialized and type(KeyForge) == "table" and type(KeyForge.new) == "function",
    "[KeyForge] SDK initialization failed: " .. tostring(KeyForge))

local client = KeyForge.new({
    projectId = "YOUR_PROJECT_ID",
    scriptId = "YOUR_SCRIPT_ID",
    integrationToken = "SIGNED_TOKEN_FROM_DASHBOARD",
})

getKeyButton.MouseButton1Click:Connect(function()
    local url, response = client:getKeyUrl()
    if url then
        setclipboard(url)
        statusLabel.Text = "Key link copied"
    else
        statusLabel.Text = response.message
    end
end)

verifyButton.MouseButton1Click:Connect(function()
    verifyButton.Active = false
    statusLabel.Text = "Checking key..."

    -- verify() solves the config challenge, then posts the key.
    local verified = client:verify(keyTextBox.Text)
    if not verified.ok then
        statusLabel.Text = verified.message
        verifyButton.Active = true
        return
    end

    statusLabel.Text = "Loading securely..."
    local loaded = client:loadScript()
    if not loaded.ok then
        statusLabel.Text = loaded.message
        verifyButton.Active = true
    end
end)

Result codes

Branch on result.ok. Show result.message to the player. Do not reimplement auth in Lua.

KEY_VALIDKey passed. Call loadScript next.
KEY_INVALIDKey does not exist or the field is empty.
KEY_EXPIREDKey is past its expiration date.
KEY_REVOKEDYou or an automated policy revoked the key.
KEY_SCRIPT_MISMATCHKey belongs to a different script.
HWID_MISMATCHKey is locked to another device.
RATE_LIMITEDToo many attempts. Wait, then retry.
SESSION_EXPIREDVerification expired. Ask for the key again.
NETWORK_ERRORExecutor could not reach KeyForge.
PROJECT_DISABLEDProject is disabled or delivery is paused.

Who does what

Your GUI: layout, animations, input, buttons, status text, and when you call the SDK.

KeyForge: key status, plan access, ad-issued keys, rate limits, HWID, executor checks, and delivery.