Developer API
Use the Sinful Management API to work with projects, licenses, and authentication logs from your own trusted backend services.
API credentials should never be embedded in Roblox, distributed Lua, or browser code. Keep them inside a trusted server environment.
Authentication
Create a scoped credential from Dashboard → API credentials. Send that credential as a Bearer token with each request.
Authorization: Bearer sm_api_YOUR_SECRET
Projects
Retrieve projects available to the authenticated API credential.
/developer/v1/projects
Required scope: projects:read
List licenses
Retrieve license records for a project.
/developer/v1/licenses?projectId=PROJECT_ID
Required scope: keys:read
The response exposes license fingerprints and status, not raw license keys.
Generate licenses
Generate license keys within the limits of the workspace's active Sinful Management plan.
/developer/v1/licenses
Required scope: keys:write
A single request can generate up to 1,000 keys, subject to plan limits.
Revoke a license
Revoke an existing license and terminate the runtime sessions attached to it.
/developer/v1/licenses/LICENSE_ID/revoke
Required scope: keys:write
Authentication logs
Read project-scoped authentication and management activity.
/developer/v1/logs?projectId=PROJECT_ID
Required scope: logs:read
Server Capabilities
Server Capabilities let a protected script request developer-controlled runtime values from Sinful Management. Capabilities are scoped to the script that owns them and are available only through an authenticated Sinful runtime.
Three capability types are available: Feature Flags, Protected Values, and Server Actions.
Open Dashboard → Scripts → Edit and enable Server Capabilities. Capabilities configured for a script are rejected at runtime while this master switch is disabled.
Creating a capability
Open Dashboard → Scripts, choose Capabilities for the script, then select New capability.
Capability names are lowercase identifiers such as
premium_enabled,
maintenance_mode, or
api_endpoint.
local value = SinfulCapability("premium_enabled")
Feature Flags
A Feature Flag is a server-controlled boolean. It returns
either true or false to the
authorized script.
Feature Flags are useful for enabling or disabling optional behavior without rebuilding and redistributing the developer's Lua source.
local premium = SinfulCapability("premium_enabled")
if premium then
print("Premium features enabled")
else
print("Premium features disabled")
end
Changing the Feature Flag in the dashboard changes the value returned by future capability requests. The developer does not need to place the flag value directly in their Lua source.
Example uses
Feature Flags can control premium features, maintenance behavior, staged rollouts, experimental functionality, or other boolean decisions that the developer wants to control from the dashboard.
Protected Values
A Protected Value stores developer-provided configuration in Sinful Management instead of placing that value directly in the uploaded Lua source.
Protected Values are encrypted when stored by Sinful Management. The dashboard capability list does not return the stored value after it has been saved.
local apiBase = SinfulCapability("api_endpoint")
print(apiBase)
Updating a Protected Value
When editing an existing Protected Value, its current value is intentionally not displayed. Enter a replacement only when you want to change it. Leaving the replacement field blank keeps the existing stored value.
A value intentionally returned to an authorized Roblox/Lua client can potentially be observed by that client. Protected Values are appropriate for server-controlled configuration, identifiers, endpoints, entitlement data, and similar runtime values. Do not use them for credentials that must never reach the client.
Master API credentials, signing private keys, database passwords, provider secrets, and similar high-value secrets should remain exclusively on a trusted server.
Server Actions
Server Actions let protected Lua request a predefined operation that Sinful Management performs on the server. Unlike a Feature Flag or Protected Value, a Server Action is not simply a stored value lookup.
Developers choose from operations implemented and allowlisted by Sinful Management. Developer-provided Lua, JavaScript, shell commands, arbitrary HTTP requests, and other arbitrary server-side code are not executed.
The operation and authoritative state change occur on the Sinful Management server. Any result intentionally returned to Lua can still be observed or modified by a hostile authorized client, so security-sensitive authority should remain in the server-side operation itself.
Using a Server Action
SinfulAction(name, input) is injected into protected
script source by Sinful Management. Use the exact Server Action
name configured for the script.
local result = SinfulAction("increment_launches")
print(result.value)
Counter Increment
Counter Increment atomically increments a named integer counter maintained by Sinful Management and returns the new value.
Configure the action with a counter name such as
launches. The client does not choose the counter name
or increment amount at runtime.
local result = SinfulAction("increment_launches")
print("Launch count:", result.value)
Counter Read
Counter Read returns the current value of a named counter without changing it.
A Counter Read action and Counter Increment action configured with the same counter name share the same authoritative state when they belong to the same project and script.
local result = SinfulAction("read_launches")
print("Launch count:", result.value)
Shared counter example
For example, configure two Server Actions:
increment_launches using Counter Increment and
read_launches using Counter Read. Set the counter
name of both actions to launches.
local before = SinfulAction("read_launches")
print("Before:", before.value)
local incremented = SinfulAction("increment_launches")
print("Incremented:", incremented.value)
local after = SinfulAction("read_launches")
print("After:", after.value)
Optional input
SinfulAction() supports an optional input table for
Server Action types that accept validated client input:
local result = SinfulAction("action_name", { })
The current Counter Read and Counter Increment handlers accept no client-controlled parameters. Passing fields to those actions is rejected.
Failure handling
Use pcall when an action is optional or when your
script should handle a runtime failure gracefully.
local ok, result = pcall(function()
return SinfulAction("read_launches")
end)
if not ok then
warn("[Sinful] Server Action failed:", result)
return
end
print(result.value)
Developers should use SinfulAction(). Sinful
Management handles runtime authentication, the short-lived
one-time action grant, context binding, grant consumption, and
execution of the allowlisted server operation.
Authorization model
Each Server Action request requires the protected authenticated runtime. Sinful Management issues a short-lived, one-time action grant bound to the current runtime context and the specific Server Action. The grant is consumed before the operation runs.
Server Actions are isolated from normal capability retrieval.
A Server Action must be called with
SinfulAction(); it cannot be retrieved through
SinfulCapability().
Using capabilities in Lua
SinfulCapability(name) is injected into protected
script source by Sinful Management before the source is
processed for distribution.
Call it from the developer source using the exact capability name configured for that script.
local enabled = SinfulCapability("premium_enabled")
local endpoint = SinfulCapability("api_endpoint")
local result = SinfulAction("increment_launches")
Recommended optional-capability pattern
If a capability controls optional functionality, developers can
use pcall and provide a safe fallback.
local function capability(name, fallback)
local ok, value = pcall(function()
return SinfulCapability(name)
end)
if not ok then
warn("[Sinful] Capability failed:", value)
return fallback
end
return value
end
local premium = capability("premium_enabled", false)
if premium then
-- premium functionality
end
Developers should use SinfulCapability().
Sinful Management handles the authenticated runtime requests,
one-time capability grant, and capability retrieval.
Capability error handling
A capability request can fail when the capability does not exist, is disabled, the script's Server Capabilities master switch is disabled, or the runtime authorization is no longer valid.
Developers should decide whether a capability is required or optional. Required configuration can stop execution on failure; optional configuration should normally use a safe fallback.
local ok, value = pcall(function()
return SinfulCapability("required_config")
end)
if not ok then
error("Required capability unavailable: " .. tostring(value))
end
Capability security model
Server Capabilities are part of the protected Sinful runtime. A normal capability lookup is not a public unauthenticated value endpoint.
The runtime first requests a short-lived capability grant. The grant is bound to the authenticated runtime context and is consumed when the capability is retrieved.
Capability retrieval uses short-lived, one-time authorization tied to the active protected runtime rather than exposing capability values through the public Developer API.
Capability isolation
Capabilities belong to a specific protected script. A script can request its own enabled capabilities through its authorized runtime context.
What this protects
Server Capabilities let developers move selected configuration and feature decisions out of static Lua source and control them from Sinful Management.
Server Actions and client trust
Server Actions can keep authoritative operations and state changes on the server instead of implementing those operations entirely in distributed Lua. Patching a local boolean does not perform the corresponding server-side operation.
However, a result returned by SinfulAction() becomes
visible to the authorized client. Client code can potentially
ignore, replace, or misrepresent that returned value. Design
security-sensitive actions so the server-side mutation or decision,
rather than trust in the returned Lua value, is authoritative.
What this does not protect
No client-side system can guarantee confidentiality after a value is intentionally delivered to a hostile authorized client. Logic or secrets that must never be exposed should remain entirely server-side.
Generate keys
Example request for generating ten 30-day license keys.
curl -X POST https://www.sinfulmanagement.com/developer/v1/licenses \
-H "Authorization: Bearer sm_api_YOUR_SECRET" \
-H "Content-Type: application/json" \
-d '{"projectId":"PROJECT_ID","scriptId":"SCRIPT_ID","quantity":10,"days":30}'
Credential security
Raw generated license keys are returned once. API credentials should also be treated as secrets.
Revoke the affected API credential immediately and issue a replacement before continuing to use the integration.