How do I make a Receipt for a developer product?

Hello. In my upcoming game I will have lots of robux items. To log purchases I have a receipt system in the making. This will send info about a purchase either to the console or to a web hook. I have set up the gamepass system but I’m not sure how to do I with developer products. This is what I did for the gamepasses. (Im very new to scripting)

local player = game.Players.LocalPlayer
script.Parent.MouseButton1Click:Connect(function()
	print("Promting Purchase!")
	wait(0)
	game:GetService("MarketplaceService"):PromptGamePassPurchase(game.Players.LocalPlayer, 14713223)
	print("Purchase Prompted!")
	local MarketplaceService = game:GetService("MarketplaceService")
	

	local gamePassID = 14713223  -- Change this to your game pass ID

	-- Function to handle a completed prompt and purchase
	local function onPromptGamePassPurchaseFinished(player, purchasedPassID, purchaseSuccess)

		if purchaseSuccess == true and purchasedPassID == gamePassID then
			print(player.Name .. " purchased the GamePass with ID: " .. gamePassID)
			-- Assign this player the ability or bonus related to the game pass
		elseif purchaseSuccess == false then
			print(player.Name .. " Started purchase Prompt for the GamePass with ID: " .. gamePassID .. " But did not buy. ")
			
		end
	end

	-- Connect "PromptGamePassPurchaseFinished" events to the "onPromptGamePassPurchaseFinished()" function
	MarketplaceService.PromptGamePassPurchaseFinished:Connect(onPromptGamePassPurchaseFinished)

end)

Worth noting that your code will leak memory. All the PromptGamePassPurchaseFinished code should not be inside your click function. Every time the button gets clicked, it’ll spawn a new connection - will be bad in the long run.

Anyway, for products you need to use ProcessReceipt to handle purchased products. There are some articles on the Developer Hub you can check out that’ll help you understand how to use it. You can save purchases and use RemoteEvents if you need to send any information to a client, such as telling them their purchase was successful along with some details about their purchase.

1 Like

so like this?

local productId = 1148733206

script.Parent.MouseButton1Click:Connect(function()
	print("Prompting Purchase!")
	wait(0)
	game:GetService("MarketplaceService"):PromptProductPurchase(game.Players.LocalPlayer, productId)
	print("Purchase Prompted!")
	local MarketplaceService = game:GetService("MarketplaceService")
	local DataStoreService = game:GetService("DataStoreService")
	local Players = game:GetService("Players")

	-- Data store for tracking purchases that were successfully processed
	local purchaseHistoryStore = DataStoreService:GetDataStore("PurchaseHistory")

	-- Table setup containing product IDs and functions for handling purchases
	local productFunctions = {}
	-- ProductId 456456 for 100 gold
	productFunctions[1148733206] = function(receipt, player)
		-- Logic/code for player buying 100 gold (may vary)
		local stats = player:FindFirstChild("leaderstats")
		local gold = stats and stats:FindFirstChild("Gold")
		if gold then
			gold.Value = gold.Value + 100
			-- Indicate a successful purchase
			return true
		end
	end

	-- The core 'ProcessReceipt' callback function
	local function processReceipt(receiptInfo)

		-- Determine if the product was already granted by checking the data store  
		local playerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId
		local purchased = false
		local success, errorMessage = pcall(function()
			purchased = purchaseHistoryStore:GetAsync(playerProductKey)
		end)
		-- If purchase was recorded, the product was already granted
		if success and purchased then
			return Enum.ProductPurchaseDecision.PurchaseGranted
		elseif not success then
			error("Data store error:" .. errorMessage)
		end

		-- Find the player who made the purchase in the server
		local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
		if not player then
			-- The player probably left the game
			-- If they come back, the callback will be called again
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end

		-- Look up handler function from 'productFunctions' table above
		local handler = productFunctions[receiptInfo.ProductId]

		-- Call the handler function and catch any errors
		local success, result = pcall(handler, receiptInfo, player)
		if not success or not result then
			warn("Error occurred while processing a product purchase")
			print("\nProductId:", receiptInfo.ProductId)
			print("\nPlayer:", player)
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end

		-- Record transaction in data store so it isn't granted again
		local success, errorMessage = pcall(function()
			purchaseHistoryStore:SetAsync(playerProductKey, true)
		end)
		if not success then
			error("Cannot save purchase data: " .. errorMessage)
		end

		-- IMPORTANT: Tell Roblox that the game successfully handled the purchase
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end

	-- Set the callback; this can only be done once by one script on the server! 
	MarketplaceService.ProcessReceipt = processReceipt
	
end)

No, because ProcessReceipt cannot be used on the client. The sample code on the page, if you want to use it whether for experimenting, modifying or full use, is intended to be in a script in ServerScriptService.

The button click should only be going as far as calling PromptProductPurchase for the product you want to be sold when the player clicks the button, it should not have anything else in it (unless you need the button to do more when it gets clicked beyond prompting the purchase).

1 Like

So I put the receipt thing in a normal script in serverscripservice?