§ How to · with Picoo

How to make a Roblox gamepass system (with AI)

By Sametcan Tasgiran, Founder & Developer·Published ·Updated

A Roblox gamepass system needs four pieces: an ownership check, perk delivery on character spawn, a purchase hook for instant grants, and a UI that shows which passes a player owns. Describe your passes and Picoo writes the scripts for them. The build below is one example of that output.

Example build: 4 files · 130 lines. Picoo writes this code for each prompt, so file names and line counts vary from run to run. Put your own pass IDs in the config before publishing.

UserOwnsGamePassAsync check

The server checks ownership when a character spawns, wrapped in pcall. A successful answer is cached for the session; a failed call is not cached, so the next spawn asks again.

Perk delivery

Each pass's onSpawn callback runs on the owner's character every time it spawns. Examples: 2x speed, a VIP chat tag, a glowing trail, extra emotes.

Instant grant on purchase

When MarketplaceService.PromptGamePassPurchaseFinished reports a purchase, the server marks the pass as owned and applies its perks right away, so a buyer does not have to rejoin.

Owned passes UI

A sidebar lists every pass with its owned status. Owned passes glow; unowned ones 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 pass ID, perk callback, display name and icon.

Periodic re-check

Once an hour the example clears its cached answers and asks MarketplaceService again, so a pass that no longer shows as owned stops granting perks from the next spawn.

Example output from a build like this

4 files in this example. Picoo writes this code for your prompt, so file names and sizes vary.

ServerScriptService/GamePassManager.lua

Ownership check, perk delivery, hourly re-check

ReplicatedStorage/Modules/GamePassConfig.lua

Per-pass IDs, perks, display info

ReplicatedStorage/Remotes/GamePassQuery

Client query for ownership state

StarterGui/GamePassUI.lua

Pass list with Buy buttons

Sample output: ServerScriptService/GamePassManager.lua

--!strict
-- ServerScriptService/GamePassManager.lua  (Picoo · 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

Gamepasses are one of the main ways a Roblox game earns Robux. Done right, they bring in steady revenue with little player friction. Done wrong, they create confusion ('did my purchase work?') and broken perk states. The example below shows the working pattern.

In this example Picoo wrote four files. GamePassConfig.lua is the data layer: each pass has a pass ID, a display name, an icon, and an onSpawn callback. Adding a gamepass is adding a config entry; the manager loops over the config, so there is nothing else to wire up.

Ownership checks are cached per session. UserOwnsGamePassAsync is a web call with latency, and calling it on every character spawn is wasteful. The example caches the first successful answer and reuses it for the rest of the session, and re-checks once an hour.

Instant grant on purchase is the polish layer. If ownership is only checked when a player joins, a new buyer has to rejoin to get their perks, and players hate that. The example listens to PromptGamePassPurchaseFinished and applies perks as soon as the purchase goes through.

The hourly re-check keeps the cache honest. If a pass that was owned no longer shows as owned, its perks stop being applied from the next spawn, with no rejoin needed.

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 is available, and that visibility is what gets passes bought.

See more on the Luau generator, the AI Luau script writer, the 3D model generator and the game builder, read how Picoo compares with ChatGPT, or browse the full blog.

Frequently asked

How do I add a new gamepass?+

Add an entry to GamePassConfig.lua keyed by the pass ID from Roblox, with name, displayName, icon and an onSpawn callback. GamePassManager loops over the config, so it picks the new pass up automatically.

What if Roblox's UserOwnsGamePassAsync errors?+

The check is wrapped in pcall. On an error it returns 'not owned', so a failed API call never hands out free perks, and it does not cache that answer, so the next spawn tries again.

How do I handle refunds?+

The example re-checks ownership once an hour. If a pass that was owned now comes back as not owned, its perks stop being applied from the next spawn.

Can I have temporary gamepasses?+

Gamepasses are permanent, so a timed perk is a Developer Product: a one-time purchase handled in MarketplaceService.ProcessReceipt, with the expiry time saved in a DataStore. Ask for timed buffs in a follow-up prompt.

How does the UI show purchase prices?+

MarketplaceService:GetProductInfo(passId, Enum.InfoType.GamePass) returns the price. GamePassUI fetches and displays it, and refreshes when the UI opens to pick up price changes.

Related Picoo prompts