Collapse Sidebar




After a player makes a purchase through a MarketplaceService/PromptProductPurchase|PromptProductPurchase() dialog, this callback is called multiple times until it returns Enum.ProductPurchaseDecision.PurchaseGranted. For example, the function is called again for a product when the player joins the game — or even after they have bought something else — unless you return Enum.ProductPurchaseDecision.PurchaseGranted. Do not return PurchaseGranted if the product could not be granted.

It’s important to carefully examine the information passed to the callback via the receipt info table and properly process the receipt. See the code sample below for a model of how to create a receipt handling callback.

Receipt Info Table

The receipt info table passed to this callback will contain the following data:

PurchaseIdstringA unique identifier for the specific purchase.
PlayerIdnumberThe ID of the player who made the purchase.
ProductIdnumberThe ID of the purchased product.
CurrencySpentnumberThe amount of currency spent in the purchase.
CurrencyTypeenum/CurrencyType|CurrencyTypeThe type of currency spent in the purchase; always Enum.CurrencyType.Robux.
PlaceIdWherePurchasednumberThe ID of the place where the product was purchased (not necessarily the same as the current place's ID).


Name Type Default Description

The receiptInfo is a table with the following keys:

  • PlayerId (number): The user ID of the player that made a purchase
  • PlaceIdWherePurchased (number): The place ID in which a purchase was made
  • PurchaseId (string): A unique identifier for a purchase that ought to be used to prevent granting a product multiple times
  • ProductId (number): The ID number of the purchased product
  • CurrencyType (Enum.CurrencyType): Deprecated. The type of currency used in the transaction.
  • CurrencySpent (number): The amount of currency spent in the transaction.

Expected return type:

Return Type Summary

An enum representing in what manner the developer product receipt was processed:

  • PurchaseGranted indicates that the game successfully granted the player the benefit the developer product is meant to provide, such as a currency boost, gameplay bonus, item, etc. This indicates to Roblox that the sale was performed successfully. Do not return PurchaseGranted if the product could not be granted.
  • NotProcessedYet indicates the developer product’s benefit could not be granted, such as a product the player is not eligible to purchase, is no longer relevant to the current game state, etc.

Code Samples

ProcessReceipt Callback

This code sample illustrates a MarketplaceService/ProcessReceipt|ProcessReceipt callback function for a game to handle purchasing of two Articles/Developer Products In Game Purchases|developer products (more can be added as needed). It properly checks for and records purchases using a GlobalDataStore called “PurchaseHistory.”

Most importantly, it properly returns Enum.ProductPurchaseDecision.PurchaseGranted when the transaction is successfully completed or if it’s detected that the purchase has already been granted using the “PurchaseHistory” data store.

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 123123 for a full heal
productFunctions[123123] = function(receipt, player)
	-- Logic/code for player buying a full heal (may vary)
	if player.Character and player.Character:FindFirstChild("Humanoid") then
		-- Heal the player to full health
		player.Character.Humanoid.Health = player.Character.Humanoid.MaxHealth
		-- Indicate a successful purchase
		return true
-- ProductId 456456 for 100 gold
productFunctions[456456] = 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

-- 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)
	-- 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)

	-- 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
	-- 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

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

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

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