Docs
Forge API
HTTP API for games and backends. Use the API key from your linked group.
Base URL
https://api.rankforge.top/api/v1
Auth header
X-API-Key: your-key
Rate limits
60/min · 10/5s burst
Get live in four moves
- Buy or claim a key from pricing.
- Link your group and authorize RankForge on the group page.
- Enable HTTP requests in Studio (Game Settings → Security).
- Call routes with
X-API-Key.
Quick status check
local HttpService = game:GetService("HttpService")
local BASE_URL = "https://api.rankforge.top/api/v1"
local response = HttpService:RequestAsync({
Url = BASE_URL .. "/status",
Method = "GET"
})
local data = HttpService:JSONDecode(response.Body)
print("API Status:", data.status)Roblox SDK (ForgeAPISDK v2)
For games, drop the ForgeAPISDK ModuleScript under ServerScriptService (keep Core, Extras, and Samples). Pass your RankForge API key from the dashboard.
local ForgeAPISDK = require(game.ServerScriptService.ForgeAPISDK)
local api = ForgeAPISDK.new({
ApiKey = "YOUR_API_KEY_HERE",
})
local status = api.System:Status()
print(status.ok, status.data and status.data.status)
local ranked = api.Ranking:Set(player, 5)
if ranked.ok then
print(ranked.data.message)
else
warn(ranked.error.code, ranked.error.message)
end
-- Namespaces: System, Ranking, Groups, Xp, Gamepass, Quota, Moderation, Events, Applications
-- Extras.QuotaDuty.bind({ api = api, dutyTeamName = "On Duty" })Endpoints
Status
/api/v1/statusPing the Forge API and confirm it is online.
Response
{
"success": true,
"status": "online",
"timestamp": "2026-01-01T00:00:00.000Z"
}Ranking
/api/v1/rankAuth requiredHard-set a Roblox user to a rank in the group bound to your key. Authorize RankForge on the group page first.
Request body
{
"userId": 123456789,
"rankId": 5
}Response
{
"success": true,
"message": "Successfully ranked user 123456789 in group 12345 to 5.",
"performedBy": "1234567890",
"result": { "name": "Member", "rank": 5 }
}Lua example
local HttpService = game:GetService("HttpService")
local API_KEY = "your-api-key-here"
local BASE_URL = "https://api.rankforge.top/api/v1"
local function rankUser(userId, rankId)
local response = HttpService:RequestAsync({
Url = BASE_URL .. "/rank",
Method = "POST",
Headers = {
["Content-Type"] = "application/json",
["X-API-Key"] = API_KEY
},
Body = HttpService:JSONEncode({
userId = userId,
rankId = rankId
})
})
return HttpService:JSONDecode(response.Body)
end
local result = rankUser(123456789, 5)
print(result.success, result.message)/api/v1/groups/:groupId/rolesAuth requiredList roles for a group your key is authorized for.
Response
{
"success": true,
"roles": [
{ "id": 123, "name": "Guest", "rank": 0 },
{ "id": 124, "name": "Member", "rank": 1 },
{ "id": 125, "name": "Admin", "rank": 255 }
]
}/api/v1/groups/:groupId/members/:userIdAuth requiredRead a member’s current rank in your group.
Response
{
"success": true,
"userId": 123456789,
"groupId": 12345,
"rank": {
"id": 5,
"name": "Member"
}
}XP & progression
/api/v1/xpAuth requiredAdd or subtract XP for a Roblox user. May auto-promote when thresholds clear.
Request body
{
"userId": 123456789,
"amount": 25
}Response
{
"success": true,
"xp": 125,
"promotion": null
}/api/v1/xp/:userIdAuth requiredRead a member’s XP and quota points.
Response
{
"success": true,
"userId": 123456789,
"xp": 125,
"quotaPoints": 3,
"quotaPeriod": "2026-W18"
}/api/v1/gamepass/claimAuth requiredCheck gamepass ownership and rank the user to the linked progression role. Omit gamePassId to sync all configured passes.
Request body
{
"userId": 123456789,
"gamePassId": 987654321
}Response
{
"success": true,
"claimed": true,
"rank": { "name": "VIP", "rank": 50 }
}Quota (in-game playtime)
/api/v1/quota/configAuth requiredMinutes per point (owner setting) and which ranks require a weekly quota.
Response
{
"success": true,
"minutesPerPoint": 30,
"period": "2026-W18",
"ranks": [{ "robloxRank": 10, "required": 5 }]
}/api/v1/quota/:userIdAuth requiredWeekly quota status for a player (points, required, Fulfilled / Not fulfilled).
Response
{
"success": true,
"userId": 123456789,
"quota": {
"points": 2,
"required": 5,
"quotaEnabled": true,
"fulfilled": false,
"statusLabel": "Not fulfilled"
}
}/api/v1/quota/session/startAuth requiredCall when the player joins the duty team. Starts the playtime timer. No heartbeats needed.
Request body
{ "userId": 123456789 }Response
{
"success": true,
"sessionActive": true,
"minutesPerPoint": 30
}Lua example
local HttpService = game:GetService("HttpService")
local API_KEY = "your-api-key-here"
local BASE = "https://api.rankforge.top/api/v1"
local function quotaRequest(path, body)
local res = HttpService:RequestAsync({
Url = BASE .. path,
Method = "POST",
Headers = {
["Content-Type"] = "application/json",
["X-API-Key"] = API_KEY,
},
Body = HttpService:JSONEncode(body),
})
return HttpService:JSONDecode(res.Body)
end
-- On Team.PlayerAdded (duty team):
quotaRequest("/quota/session/start", { userId = player.UserId })
-- On leave team / PlayerRemoving:
quotaRequest("/quota/session/stop", { userId = player.UserId })/api/v1/quota/session/stopAuth requiredCall when the player leaves the duty team (also on PlayerRemoving). Awards floor(elapsed / minutesPerPoint).
Request body
{ "userId": 123456789 }Response
{
"success": true,
"sessionActive": false,
"awarded": 2,
"elapsedSeconds": 3900,
"minutesPerPoint": 30,
"quota": { "points": 2, "required": 5, "statusLabel": "Not fulfilled" }
}Moderation
/api/v1/moderationAuth requiredWarn, suspend, unsuspend, blacklist, or unblacklist a Roblox user.
Request body
{
"action": "warn",
"userId": 123456789,
"reason": "Spam",
"durationHours": 24
}Response
{
"success": true,
"result": { "ok": true }
}Events
/api/v1/eventsAuth requiredList events. Optional query: status, limit (default 30).
Response
{
"success": true,
"events": [
{
"_id": "…",
"name": "Training",
"status": "active",
"xpAward": 10,
"quotaAward": 1
}
]
}/api/v1/eventsAuth requiredCreate an event.
Request body
{
"name": "Training",
"type": "drill",
"startsAt": "2026-05-01T18:00:00.000Z",
"xpAward": 10,
"quotaAward": 1
}Response
{
"success": true,
"event": { "_id": "…", "name": "Training", "status": "active" }
}/api/v1/events/:eventId/attendAuth requiredMark attendance for a Roblox user.
Request body
{
"userId": 123456789,
"discordId": "optional"
}Response
{
"success": true,
"attended": true
}/api/v1/events/:eventId/finishAuth requiredFinish an event and award XP / quota to attendees.
Response
{
"success": true,
"awarded": 12
}Applications
/api/v1/applicationsAuth requiredList application responses. Optional query: status (default pending), limit.
Response
{
"success": true,
"applications": [
{ "_id": "…", "status": "pending", "robloxUserId": 123456789 }
]
}/api/v1/applications/:responseId/reviewAuth requiredPass or fail an application response.
Request body
{
"pass": true,
"note": "Welcome"
}Response
{
"success": true,
"application": { "_id": "…", "status": "passed" }
}Errors & limits
| Code | Meaning |
|---|---|
| 400 | Bad request, missing or invalid body fields. |
| 401 | Unauthorized, missing X-API-Key header. |
| 403 | Forbidden, key expired, revoked, or wrong group. |
| 429 | Rate limited by RankForge, respect Retry-After / remaining headers. Separate from Roblox Open Cloud limits (those are retried server-side). |
| 500 | Internal or upstream failure after RankForge already retried Roblox. Safe to retry with backoff. |
| 502 | Roblox Open Cloud failed after retries (rate limit or outage). Retry later with backoff. |
Limits
- Per API key60 / min
- Burst10 / 5s
- Unauthed IP120 / min
Response headers
X-RateLimit-LimitMax requests in the window
X-RateLimit-RemainingRequests left in this window
X-RateLimit-ResetSeconds until the window resets
Retry-AfterWait seconds after a 429
Roblox Open Cloud
Ranking writes (promote, demote, joins) call Roblox Open Cloud from Ranking-API. RankForge retries those upstream calls on 429 and transient 5xx, preferring Roblox's Retry-After header, otherwise exponential backoff with jitter (up to 3 retries). Permanent client errors (400 / 401 / 403 / 404) are not retried.
Still handle RankForge 429s
429, wait for Retry-After before calling again.