How to use developer products in Roblox (ProcessReceipt that never double-grants)
Short answer
Create the product in Creator Hub > Monetization, prompt it with MarketplaceService:PromptProductPurchase, and grant it only in MarketplaceService.ProcessReceipt. Record each PurchaseId in a DataStore, grant and save the item, and only then return PurchaseGranted; return NotProcessedYet if anything fails so Roblox retries. Roblox warns not to grant from PromptProductPurchaseFinished.
Copy-paste code
ServerScriptService/Purchases.server.lua
local MarketplaceService = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local receipts = DataStoreService:GetDataStore("Receipts_v1")
local GRANTS = {
[123456789] = function(player) -- your developer product id
player.leaderstats.Coins.Value += 500
return true
end,
}
MarketplaceService.ProcessReceipt = function(info)
local player = Players:GetPlayerByUserId(info.PlayerId)
local grant = GRANTS[info.ProductId]
if not player or not grant then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local granted = false
local ok = pcall(receipts.UpdateAsync, receipts, info.PlayerId .. "_" .. info.PurchaseId, function(already)
if already then granted = true return nil end -- granted on an earlier call
if not grant(player) then return nil end
granted = true
return true
end)
if ok and granted then
return Enum.ProductPurchaseDecision.PurchaseGranted
end
return Enum.ProductPurchaseDecision.NotProcessedYet
end
-- client: MarketplaceService:PromptProductPurchase(player, 123456789)Good to know
ProcessReceipt can be called again for the same purchase, for example after a server crash or when the player rejoins. The PurchaseId record is what stops a second grant.
Only one script may set ProcessReceipt. Put every product in that one GRANTS table.
Roblox checks Listed products' ProcessReceipt and stops showing a product outside your game if it detects a problem.
Studwright: Roblox systems that never lose saves
from $12Studwright's Receipts module grants developer products exactly once and saves the grant with the player's session-locked data. 16 tested modules in one kit.
Secure checkout · 14-day fix-or-refund if it doesn't work as described (terms)Questions
Developer product or game pass?
Developer products can be bought many times (coins, boosts); game passes are bought once (VIP, a permanent perk).
Why not use PromptProductPurchaseFinished?
It only tells you the prompt closed; Roblox's docs say to grant purchases in ProcessReceipt.
How much do I keep?
Roblox keeps 30% of each sale; you keep 70% as Earned Robux.
Free: the Roblox Starter Kit
7 free Luau modules (damage, pets, shop formatting, admin audit log, tycoon guards and more) plus 3 free calculators, then 5 short emails with the scripting fixes we see go wrong most often.