Manage whitelists and blacklists from code, and check players from your own loader.
Overview
The Spectra seller API lets you manage your own scripts' whitelist and blacklist from code, and lets your in-game loader ask whether a player is whitelisted or blacklisted.
Base URL
https://spectra.dreamforger.xyz/api
Format
JSON requests and responses (Content-Type: application/json on request bodies)
Management auth
X-API-Key header (your seller API key)
Check API auth
token query parameter (a per-script check token), no header
Plan
Adding to a whitelist/blacklist and the Check API need a Premium or Lifetime plan. Listing and removing work on any plan.
Rate limit
60 requests per minute on /seller/*
Two separate APIs live here. Use the Whitelist and Blacklist sections from your own backend or tooling. Use the Check API section from inside a Roblox script.
# list your scripts
curl -H "X-API-Key: YOUR_API_KEY" https://spectra.dreamforger.xyz/api/seller/scripts
Authentication
Seller API key (management). Send it on every /seller/* request:
Keys are created while you are signed in to the dashboard, with POST /seller/api-keys (session login required; body {"label": "my bot"}). The full key is shown once in that response and only a hash is stored, so save it immediately. List your keys with GET /seller/api-keys and revoke one with DELETE /seller/api-keys/{key_id}. Those three routes use your dashboard session, not an API key.
Check token (Check API). A separate, read-only credential scoped to one script. Get or rotate it in Discord with the /checktoken command (script_id, optional rotate). It is meant to be embedded in a script players can read, so it can only answer whitelist/blacklist questions and nothing else.
Never put your X-API-Key in a script players can read. Only the check token is safe to embed.
Scripts
Every whitelist and blacklist route is keyed by the numeric script id. This is the only route that lists those ids.
For your own in-game loader: ask whether a player is whitelisted or blacklisted for one script. Read-only, authenticated by a check token instead of an API key.
GET/check/statusCheck one player
Auth: token query param (no header)
Name
In
Type
Description
token
query
string
Your script's check token (Discord /checktoken).
user
query
string
Roblox username to look up (max 100 chars, case-insensitive).
Always HTTP 200. A bad/rotated token, missing params, an owner below Premium, and being rate-limited all return {"whitelisted": null, "blacklisted": null}, on purpose, so the API can't be used to probe which tokens exist.
null means "couldn't verify right now". It is not the same as false. Decide in your loader whether unknown should fail open or closed.
Rate limit: 20 requests per 10 seconds per token. Call once per player join, not in a loop.
Ready-made Lua client. Instead of writing the HTTP calls yourself, load the official client from inside your Roblox script:
local SpecProtect = loadstring(game:HttpGet(
"https://spectra.dreamforger.xyz/api/loader/specprotect.lua"
))("YOUR_CHECK_TOKEN")
local name = game.Players.LocalPlayer.Name
if SpecProtect.is_blacklisted(name) then
return -- blocked
end
if not SpecProtect.is_whitelisted(name) then
return -- not allowed
end
-- raw result, if you want to handle null yourself:
local status = SpecProtect.check_status(name)
-- status.whitelisted / status.blacklisted can be true, false or nil
Function
Unknown result (nil) is treated as
is_whitelisted(user)
false (fails closed)
is_blacklisted(user)
false (fails open)
check_status(user)
returns the raw table, nil fields preserved
Honest limit: this proves the caller holds your check token, not that they are an untampered Roblox client. If the code around the check lives in a plain unprotected script, someone can delete the check. It is a convenience for custom loaders, not a replacement for protecting the script itself.
Errors
Errors from /seller/* return JSON like {"detail": "Script not found."} with these status codes:
Status
Meaning
401
X-API-Key header missing, invalid, or revoked.
403
Your plan doesn't include this action (adding to whitelist/blacklist needs Premium or Lifetime).
404
Script id isn't yours, or the entry id doesn't exist on that script.
400
Bulk request had no valid usernames after cleaning.
422
Request body failed validation (wrong field name/type, empty or oversized list, username over 100 chars).
429
Rate limit exceeded (60/min on /seller/*). Back off and retry.
/check/status is the exception: it never returns an error status. See the Check API section.
A machine-readable OpenAPI schema of everything on this page is available at /openapi.json.
# Spectra Seller API
Base URL: `https://spectra.dreamforger.xyz/api`
This document describes the public Spectra seller API. It is written to be pasted into an AI agent's context. All paths below are relative to the base URL.
## Overview
The Spectra seller API lets you manage your own scripts' whitelist and blacklist from code, and lets your in-game loader ask whether a player is whitelisted or blacklisted.
| | |
|---|---|
| Base URL | `https://spectra.dreamforger.xyz/api` |
| Format | JSON requests and responses (`Content-Type: application/json` on request bodies) |
| Management auth | `X-API-Key` header (your seller API key) |
| Check API auth | `token` query parameter (a per-script check token), no header |
| Plan | Adding to a whitelist/blacklist and the Check API need a Premium or Lifetime plan. Listing and removing work on any plan. |
| Rate limit | 60 requests per minute on `/seller/*` |
Two separate APIs live here. Use the **Whitelist** and **Blacklist** sections from your own backend or tooling. Use the **Check API** section from inside a Roblox script.
```bash
# list your scripts
curl -H "X-API-Key: YOUR_API_KEY" https://spectra.dreamforger.xyz/api/seller/scripts
```
## Authentication
**Seller API key** (management). Send it on every `/seller/*` request:
```http
X-API-Key: spak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
Keys are created while you are signed in to the dashboard, with `POST /seller/api-keys` (session login required; body `{"label": "my bot"}`). The full key is shown **once** in that response and only a hash is stored, so save it immediately. List your keys with `GET /seller/api-keys` and revoke one with `DELETE /seller/api-keys/{key_id}`. Those three routes use your dashboard session, not an API key.
**Check token** (Check API). A separate, read-only credential scoped to one script. Get or rotate it in Discord with the `/checktoken` command (`script_id`, optional `rotate`). It is meant to be embedded in a script players can read, so it can only answer whitelist/blacklist questions and nothing else.
> Never put your `X-API-Key` in a script players can read. Only the check token is safe to embed.
## Scripts
Every whitelist and blacklist route is keyed by the numeric script id. This is the only route that lists those ids.
### GET /seller/scripts
List your scripts. Auth: X-API-Key.
Example:
```bash
curl -H "X-API-Key: YOUR_API_KEY" \
https://spectra.dreamforger.xyz/api/seller/scripts
```
Response `200`:
```json
[
{
"id": 54,
"name": "My Script",
"tier_used": "premium",
"enabled": true,
"is_free": false,
"anti_dump": true,
"two_stage": false,
"created_at": "2026-09-01T12:00:00Z",
"updated_at": "2026-10-09T09:30:00Z"
}
]
```
- Only the most useful fields are shown above; more per-script settings are returned. The secret `vm_token` is never included.
## Whitelist
Players on a script's whitelist are allowed to run it. Usernames are matched case-insensitively.
### GET /seller/whitelist/{script_id}
List whitelist entries. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Example:
```bash
curl -H "X-API-Key: YOUR_API_KEY" \
https://spectra.dreamforger.xyz/api/seller/whitelist/54
```
Response `200`:
```json
[
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"revoked": false,
"created_at": "2026-10-10T18:22:04.113Z",
"hwid": null,
"last_used_at": null
}
]
```
- Includes revoked entries (`revoked: true`). `hwid` is filled in after the player first runs the script.
### POST /seller/whitelist/{script_id}
Add one username. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_username": "SomePlayer"
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_username":"SomePlayer"}' \
https://spectra.dreamforger.xyz/api/seller/whitelist/54
```
Response `201`:
```json
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"revoked": false,
"created_at": "2026-10-10T18:22:04.113Z"
}
```
- Re-adding a previously revoked username un-revokes it.
- Premium/Lifetime only (403 otherwise).
### POST /seller/whitelist/{script_id}/bulk
Add many usernames. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_usernames": [
"SomePlayer",
"AnotherPlayer"
]
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_usernames":["SomePlayer","AnotherPlayer"]}' \
https://spectra.dreamforger.xyz/api/seller/whitelist/54/bulk
```
Response `201`:
```json
{
"added": [
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"revoked": false,
"created_at": "2026-10-10T18:22:04.113Z"
}
],
"count": 1
}
```
- Up to 200 usernames per request. Blanks and case-insensitive duplicates are dropped; 400 if nothing valid remains.
- Premium/Lifetime only.
### POST /seller/whitelist/{script_id}/bulk-remove
Remove many usernames. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_usernames": [
"SomePlayer"
]
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_usernames":["SomePlayer"]}' \
https://spectra.dreamforger.xyz/api/seller/whitelist/54/bulk-remove
```
Response `200`:
```json
{
"revoked": 1
}
```
- Same 200-username cap and cleaning as bulk add.
### DELETE /seller/whitelist/{script_id}/{whitelist_id}
Remove one entry by id. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
| `whitelist_id` | path | integer | The entry's `id` from the list route. |
Example:
```bash
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
https://spectra.dreamforger.xyz/api/seller/whitelist/54/17
```
Response `204`:
```json
(empty body)
```
- Revokes the entry. 404 if the id isn't an entry on that script.
## Blacklist
Blacklisted players are blocked from running the script, even if they would otherwise qualify.
### GET /seller/blacklist/{script_id}
List blacklist entries. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Example:
```bash
curl -H "X-API-Key: YOUR_API_KEY" \
https://spectra.dreamforger.xyz/api/seller/blacklist/54
```
Response `200`:
```json
[
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"created_at": "2026-10-10T18:22:04.113Z"
}
]
```
### POST /seller/blacklist/{script_id}
Add one username. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_username": "BadActor"
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_username":"BadActor"}' \
https://spectra.dreamforger.xyz/api/seller/blacklist/54
```
Response `201`:
```json
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"created_at": "2026-10-10T18:22:04.113Z"
}
```
- Adding someone already blacklisted just returns their existing entry.
- Premium/Lifetime only.
### POST /seller/blacklist/{script_id}/bulk
Add many usernames. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_usernames": [
"BadActor",
"AnotherOne"
]
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_usernames":["BadActor","AnotherOne"]}' \
https://spectra.dreamforger.xyz/api/seller/blacklist/54/bulk
```
Response `201`:
```json
{
"added": [
{
"id": 17,
"script_name": "My Script",
"roblox_username": "SomePlayer",
"created_at": "2026-10-10T18:22:04.113Z"
}
],
"count": 1
}
```
- Up to 200 usernames per request.
- Premium/Lifetime only.
### POST /seller/blacklist/{script_id}/bulk-remove
Remove many usernames. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
Request body:
```json
{
"roblox_usernames": [
"BadActor"
]
}
```
Example:
```bash
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"roblox_usernames":["BadActor"]}' \
https://spectra.dreamforger.xyz/api/seller/blacklist/54/bulk-remove
```
Response `200`:
```json
{
"removed": 1
}
```
### DELETE /seller/blacklist/{script_id}/{blacklist_id}
Remove one entry by id. Auth: X-API-Key.
| Name | In | Type | Description |
|---|---|---|---|
| `script_id` | path | integer | Numeric id of one of your scripts (from `GET /seller/scripts`). |
| `blacklist_id` | path | integer | The entry's `id` from the list route. |
Example:
```bash
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
https://spectra.dreamforger.xyz/api/seller/blacklist/54/17
```
Response `204`:
```json
(empty body)
```
- 404 if the id isn't an entry on that script.
## Check API
For your own in-game loader: ask whether a player is whitelisted or blacklisted for one script. Read-only, authenticated by a check token instead of an API key.
### GET /check/status
Check one player. Auth: token query param (no header).
| Name | In | Type | Description |
|---|---|---|---|
| `token` | query | string | Your script's check token (Discord `/checktoken`). |
| `user` | query | string | Roblox username to look up (max 100 chars, case-insensitive). |
Example:
```bash
curl "https://spectra.dreamforger.xyz/api/check/status?token=YOUR_CHECK_TOKEN&user=SomePlayer"
```
Response `200`:
```json
{
"whitelisted": true,
"blacklisted": false
}
```
- **Always HTTP 200.** A bad/rotated token, missing params, an owner below Premium, and being rate-limited all return `{"whitelisted": null, "blacklisted": null}`, on purpose, so the API can't be used to probe which tokens exist.
- `null` means "couldn't verify right now". It is **not** the same as `false`. Decide in your loader whether unknown should fail open or closed.
- Rate limit: 20 requests per 10 seconds per token. Call once per player join, not in a loop.
**Ready-made Lua client.** Instead of writing the HTTP calls yourself, load the official client from inside your Roblox script:
```lua
local SpecProtect = loadstring(game:HttpGet(
"https://spectra.dreamforger.xyz/api/loader/specprotect.lua"
))("YOUR_CHECK_TOKEN")
local name = game.Players.LocalPlayer.Name
if SpecProtect.is_blacklisted(name) then
return -- blocked
end
if not SpecProtect.is_whitelisted(name) then
return -- not allowed
end
-- raw result, if you want to handle null yourself:
local status = SpecProtect.check_status(name)
-- status.whitelisted / status.blacklisted can be true, false or nil
```
| Function | Unknown result (nil) is treated as |
|---|---|
| `is_whitelisted(user)` | `false` (fails closed) |
| `is_blacklisted(user)` | `false` (fails open) |
| `check_status(user)` | returns the raw table, nil fields preserved |
> Honest limit: this proves the caller holds your check token, not that they are an untampered Roblox client. If the code around the check lives in a plain unprotected script, someone can delete the check. It is a convenience for custom loaders, not a replacement for protecting the script itself.
## Errors
Errors from `/seller/*` return JSON like `{"detail": "Script not found."}` with these status codes:
| Status | Meaning |
|---|---|
| `401` | `X-API-Key` header missing, invalid, or revoked. |
| `403` | Your plan doesn't include this action (adding to whitelist/blacklist needs Premium or Lifetime). |
| `404` | Script id isn't yours, or the entry id doesn't exist on that script. |
| `400` | Bulk request had no valid usernames after cleaning. |
| `422` | Request body failed validation (wrong field name/type, empty or oversized list, username over 100 chars). |
| `429` | Rate limit exceeded (60/min on `/seller/*`). Back off and retry. |
`/check/status` is the exception: it never returns an error status. See the Check API section.
A machine-readable OpenAPI schema of everything on this page is available at `/openapi.json`.