Skinstashery
Roblox
Home / Roblox / Studio script library / Developer product handler
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
end

How to set it up

  1. On the Creator Dashboard, open your game, go to Monetization > Developer Products and create a product. Copy its ID.
  2. Put the ID in place of the 0 in productHandlers. Add more entries for more products.
  3. Add the Script to ServerScriptService. Turn on Studio Access to API Services in Game Settings > Security.
  4. To start a purchase, call MarketplaceService:PromptProductPurchase(player, productId) from a button or ProximityPrompt script.

Change it

More in Player data and money

All Roblox scripts

More Roblox tools