§ How to · with Forge AI

How to make a Roblox gamepass system (with AI)

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

A Roblox gamepass system needs four pieces: ownership check on join, perk delivery on character spawn, purchase hook for instant grants, and a UI to display owned passes. Forge AI generates all four in 38 seconds.

4 files · 130 lines · 38 seconds · 1 credit. Production-ready monetization layer.

UserOwnsGamePassAsync check

Server checks ownership on PlayerAdded with retry-on-fail. Result cached per session to avoid repeated API calls.

Perk delivery

Perk callbacks fire on character spawn for owners. Examples: 2x speed, VIP chat tag, glowing trail, custom emote unlocks.

Instant grant on purchase

GamePassPurchaseFinished event triggers immediate perk delivery — no rejoin required. Player sees their perks the moment the Robux transaction confirms.

Owned passes UI

Sidebar panel shows all gamepasses with owned status. Owned passes glow; unowned have a 'Buy' button that opens the Robux purchase prompt.

Multi-pass support

Add as many gamepasses as you want by extending GamePassConfig. Each has its own asset ID, perk callback, and display name/icon.

Anti-refund handling

If a player refunds a gamepass, the ownership cache invalidates and perks revoke. Polled hourly + on character spawn.

Files Forge AI ships for this prompt

4 files · 130 lines · 38 seconds · 1 credit

ServerScriptService/GamePassManager.lua

Ownership check, perk delivery, refund handling

58 lines

ReplicatedStorage/Modules/GamePassConfig.lua

Per-pass asset IDs, perks, display info

38 lines

ReplicatedStorage/Remotes/GamePassQuery

Client query for ownership state

instance

StarterGui/GamePassUI.lua

Pass list with Buy buttons

34 lines

Sample output: ServerScriptService/GamePassManager.lua

--!strict
-- ServerScriptService/GamePassManager.lua  (Forge AI · excerpt)
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Config = require(ReplicatedStorage.Modules.GamePassConfig)

local owned: { [Player]: { [number]: boolean } } = {}

local function checkOwnership(player: Player, passId: number): boolean
    if owned[player] and owned[player][passId] ~= nil then
        return owned[player][passId]
    end
    local ok, result = pcall(function()
        return MarketplaceService:UserOwnsGamePassAsync(player.UserId, passId)
    end)
    if ok then
        owned[player] = owned[player] or {}
        owned[player][passId] = result
        return result
    end
    return false
end

local function applyPerks(player: Player)
    if not player.Character then return end
    for passId, def in pairs(Config) do
        if checkOwnership(player, passId) and def.onSpawn then
            def.onSpawn(player.Character)
        end
    end
end

Players.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function(_) applyPerks(player) end)
end)

MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player: Player, passId: number, wasPurchased: boolean)
    if not wasPurchased then return end
    owned[player] = owned[player] or {}
    owned[player][passId] = true
    applyPerks(player)
end)

Building a Roblox gamepass system

Gamepass systems are the highest-margin monetization layer in Roblox. Done right, they generate consistent Robux revenue with minimal player friction. Done wrong, they create confusion ('did my purchase work?'), refund spirals, and broken perk states. Forge AI ships the working pattern.

The Forge AI gamepass prompt produces a 4-file system in 38 seconds. GamePassConfig.lua is the data layer — each pass has an asset ID, a display name, an icon, and an onSpawn callback. Adding a new gamepass is adding a config entry; the engine handles everything else.

Ownership checks are cached per session. UserOwnsGamePassAsync is a real API call with latency and rate limits. Hitting it on every character spawn would be wasteful. Forge's pattern caches the result on first check and reuses it for the rest of the session — with an hourly background refresh to catch refunds.

Instant grant on purchase is the polish layer. The default Roblox flow is: player clicks Buy → Robux deducts → next time they rejoin, perks apply. Players hate the rejoin requirement. Forge listens to GamePassPurchaseFinished and applies perks immediately, so the player sees their purchase reflected in seconds.

Refund handling is the integrity layer. Players occasionally refund gamepasses via Roblox support. The system needs to revoke perks when this happens — otherwise refunded players keep their advantages indefinitely. Forge polls ownership hourly and revokes on character spawn. This is invisible to legitimate players (they never refund) but catches the abuse pattern cleanly.

The UI surfaces ownership state. A sidebar panel lists every gamepass with an owned/unowned status. Unowned passes show a Buy button that triggers the Robux purchase prompt. Owned passes glow with a checkmark. Players can see at a glance what they have and what's available — which is exactly the discoverability that drives conversions.

See more on the Luau generator, the game builder, or browse the full blog.

Frequently asked

How do I add a new gamepass?+

Add an entry to GamePassConfig.lua: passId (number from Roblox), name, displayName, icon, onSpawn callback. GamePassManager picks it up automatically.

What if Roblox's UserOwnsGamePassAsync errors?+

The check is wrapped in pcall. On error, default to 'not owned' (safe default — no free perks if the API fails). Cache is not poisoned, so the next attempt retries. Hourly background refresh ensures eventual consistency.

How do I handle refunds?+

GamePassManager polls ownership hourly per player. If a previously-owned pass now returns false, perks are removed on the next character spawn. Players cannot exploit by buying-then-refunding to keep perks.

Can I have temporary gamepasses?+

Yes. Use DeveloperProducts for one-time purchases with a server-side expiration timer stored in DataStore. GamePassConfig can mix permanent passes with timed buffs.

How does the UI show purchase prices?+

MarketplaceService:GetProductInfo(passId, Enum.InfoType.GamePass) returns the price. GamePassUI fetches and displays it. Refreshes on UI open to handle price changes.

Related Forge AI prompts