FFORGEBLOX

Guide · 8 min read · Updated October 2026

Game pass and developer product scripts with AI, done right

Monetization is the part of a Roblox game that AI script generators get wrong most often, and the part exploiters look at first. This guide gives you the one prompt that wires game passes and developer products correctly, shows the Luau a good agent should produce, and explains the three rules that make it exploit-resistant. It works in any Roblox Studio AI tool that can edit your place; the prompt is written for ForgeBlox.

Passes vs products in one table

Game passDeveloper product
BoughtOnce, owned foreverMany times, consumable
ExamplesVIP, 2x Coins, Auto Collect, a skin500 Coins, Skip Stage, Revive
CheckUserOwnsGamePassAsync once on join (in a pcall), plus PromptGamePassPurchaseFinished to grant instantlyMarketplaceService.ProcessReceipt on the server, exactly one in the whole game
Prompt fromClient: PromptGamePassPurchaseClient: PromptProductPurchase
Typical price2x pass 199–399 R$, VIP 399–799 R$Coin packs 25–99 R$, skip stage 25–49 R$

The three rules

  1. Exactly one ProcessReceipt. It is a single callback. A second assignment anywhere in the game silently replaces the first, and purchases vanish. Keep it in ServerScriptService/Monetization and route every product through a table.
  2. Grant idempotently, on the server, before returning. Roblox retries receipts. Record the purchase id in a DataStore, grant through your economy module so it is saved with the player data, and only then return PurchaseGranted. The client never sends anything about a purchase.
  3. One config module for ids. Put every pass and product id in ReplicatedStorage/Config/Products. The AI writes placeholder ids; you create the real ones in the Creator Dashboard and paste them in.

The prompt

Add monetization to this place. Create ReplicatedStorage/Config/Products with
placeholder ids: game passes VIP (2x coins) and AutoCollect; developer products
Coins500, Coins2000, SkipStage. On join, check each pass with
UserOwnsGamePassAsync in a pcall and cache it in the player's data; also handle
PromptGamePassPurchaseFinished to grant immediately. Put the ONLY
MarketplaceService.ProcessReceipt in ServerScriptService/Monetization: look up
the product in a grants table, record receipt.PurchaseId in a PurchaseHistory
DataStore so a retry never double-grants, grant through the Economy module so it
is saved with the player, and return PurchaseGranted only after the save. Add a
Shop HUD with real prices from GetProductInfo (cached, pcall). Test one pass and
one product with Studio test purchases, screenshot the shop and the console.

What the agent should produce

The core of the server script looks like this. If your tool produced something that grants from a LocalScript, or that has no purchase-history check, send the prompt again with "fix ProcessReceipt to be idempotent and server-only."

local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local Economy = require(game.ServerScriptService.Economy)
local Products = require(game.ReplicatedStorage.Config.Products)
local purchaseHistory = DataStoreService:GetDataStore("PurchaseHistory_v1")

local grants = {
	[Products.Coins500] = function(player) Economy.AddCoins(player, 500, "product:Coins500") end,
	[Products.Coins2000] = function(player) Economy.AddCoins(player, 2000, "product:Coins2000") end,
	[Products.SkipStage] = function(player) Economy.SkipStage(player, 1) end,
}

MarketplaceService.ProcessReceipt = function(receipt)
	local player = Players:GetPlayerByUserId(receipt.PlayerId)
	if not player then return Enum.ProductPurchaseDecision.NotProcessedYet end -- retried when they rejoin
	local key = receipt.PlayerId .. "_" .. receipt.PurchaseId
	local ok, already = pcall(purchaseHistory.GetAsync, purchaseHistory, key)
	if not ok then return Enum.ProductPurchaseDecision.NotProcessedYet end
	if already then return Enum.ProductPurchaseDecision.PurchaseGranted end -- idempotent
	local grant = grants[receipt.ProductId]
	if not grant then return Enum.ProductPurchaseDecision.NotProcessedYet end
	local granted = pcall(grant, player)
	if not granted then return Enum.ProductPurchaseDecision.NotProcessedYet end
	pcall(purchaseHistory.SetAsync, purchaseHistory, key, true)
	return Enum.ProductPurchaseDecision.PurchaseGranted
end

Two details worth noticing: NotProcessedYet is returned whenever anything is uncertain, because Roblox will retry and that is the safe outcome; and the grant goes through Economy, the same module the rest of the game uses, so the reward is saved with the player data rather than in a separate place that can drift.

Testing before you publish

Pricing guidance

Common ranges from published Roblox games in 2026: a 2x pass at 199–399 Robux, VIP at 399–799, small coin packs at 25–99, skip-stage at 25–49. Show the real price with GetProductInfo(id, Enum.InfoType.Product).PriceInRobux, in a pcall, cached, rather than hard-coding it in the UI.

See it in context: the tycoon guide adds a shop in message 4, the obby guide adds skip-stage, and the simulator guide adds a 2x pass. Costs are on the pricing page.

Related guides

Ask ForgeBlox to audit your existing shop. "Review this place's monetization: find every ProcessReceipt, every client-side grant, and every untrusted remote" usually costs under 100 credits. Open ForgeBlox →