RB-004
Roblox developer product handler script
Gives players coins when they buy a developer product, using ProcessReceipt the safe way.
- Script type
- Script
- Where it goes
- ServerScriptService
- Category
- Player data and money
For your own game in Roblox Studio. Not for use in other people's games.
The code
-- Developer product handler: ProcessReceipt.
-- Developer products can be bought many times (unlike game passes).
-- Roblox keeps calling ProcessReceipt until you return PurchaseGranted.
-- Needs player.leaderstats.Coins (use the Save data script, or coins are lost when the player leaves).
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local receiptStore = DataStoreService:GetDataStore("Receipts_v1")
local function addCoins(player, amount)
local leaderstats = player:FindFirstChild("leaderstats")
local coins = leaderstats and leaderstats:FindFirstChild("Coins")
if not coins then
return false
end
coins.Value += amount
return true
end
-- [product ID] = function that gives the reward. It must return true if it worked.
local productHandlers = {
[0] = function(player) -- replace 0 with your developer product ID (100 coins)
return addCoins(player, 100)
end,
-- [0] = function(player) -- another product (1000 coins)
-- return addCoins(player, 1000)
-- end,
}
MarketplaceService.ProcessReceipt = function(receiptInfo)
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
-- The player left. Roblox will ask again when they rejoin.
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Has this exact purchase already been given?
local key = receiptInfo.PlayerId .. "_" .. tostring(receiptInfo.PurchaseId)
local readOk, alreadyGiven = pcall(function()
return receiptStore:GetAsync(key)
end)
if not readOk then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
if alreadyGiven then
return Enum.ProductPurchaseDecision.PurchaseGranted
end
local handler = productHandlers[receiptInfo.ProductId]
if not handler then
warn("No handler for product ID " .. tostring(receiptInfo.ProductId))
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local grantOk, granted = pcall(handler, player)
if not grantOk or not granted then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- Remember the purchase so it is never given twice.
local writeOk, writeError = pcall(function()
receiptStore:SetAsync(key, true)
end)
if not writeOk then
warn("Could not record receipt " .. key .. ": " .. tostring(writeError))
end
return Enum.ProductPurchaseDecision.PurchaseGranted
endHow to set it up
- On the Creator Dashboard, open your game, go to Monetization > Developer Products and create a product. Copy its ID.
- Put the ID in place of the 0 in productHandlers. Add more entries for more products.
- Add the Script to ServerScriptService. Turn on Studio Access to API Services in Game Settings > Security.
- To start a purchase, call MarketplaceService:PromptProductPurchase(player, productId) from a button or ProximityPrompt script.
Change it
- Only one script in your whole game may set ProcessReceipt. If you have two, only the last one wins.
- Returning NotProcessedYet is safe. Roblox will try again later, so the player does not lose their Robux.
- The receipt store stops a double reward if Roblox calls ProcessReceipt twice for the same purchase.
- In a real game, store a purchase log with the player's save data if you want to refund or check later.
More in Player data and money
More Roblox tools
- Shirt and pants templatesFree Roblox clothing templates to download: hoodies, jerseys, jeans, joggers and more.
- Robux tax calculatorWork out what you receive after the marketplace fee, or what to charge.
- Robux to USD calculatorConvert earned Robux to dollars at a DevEx rate you can edit.
- Shirt and pants template makerColour each panel of the 585×559 clothing template and download it.
- Username generatorGenerate usernames that fit the 3–20 character rule.