ProcessReceipt fires multiple times with each product purchase

function StoreService:ProcessProduct(receiptInfo)
    if true then -- checks/whatever, returns true in my instance
        print("BUY")
        return true
    end

	return false, "Failed to find product to give for " .. receiptInfo.ProductId
end

local function ProcessReceipt(receiptInfo)
	--[[
       Receipt Info:
           PlayerId: number
           ProductId: number
           PurchaseId: string
           CurrencySpent: number
           PlaceIdWherePurchased: number
   	--]]
		-- Determine if the product was already granted by checking the data store
	local PlayerProductKey = receiptInfo.PlayerId .. "_" .. receiptInfo.PurchaseId

	local Success, IsPurchaseRecorded = pcall(function()
		return PurchaseHistoryStore:UpdateAsync(PlayerProductKey, function(alreadyPurchased)
			if alreadyPurchased then
				return true
			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 nil
			end

			local Processed, Result = self:ProcessProduct(receiptInfo)
			if not Processed then -- Granting the product failed, do NOT record the purchase
				warn(
					"Failed to process a product purchase for ProductId:",
					receiptInfo.ProductId,
					" Player:",
					Player,
					Result
				)

				return nil
			end
			-- Product successfully purchased + reward given to player
			self.Client.ProductPurchased:Fire(Player, receiptInfo) -- Client fire
			self.ProductPurchased:Fire(receiptInfo) -- Server fire
			return true
		end)
	end)

	if not Success then
		error("Failed to process receipt due to data store error.")

		return Enum.ProductPurchaseDecision.NotProcessedYet
	elseif IsPurchaseRecorded == nil then -- Didn't update the value in data store.
		return Enum.ProductPurchaseDecision.NotProcessedYet
	else -- IMPORTANT: Tell Roblox that the game successfully handled the purchase
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end
end

MarketplaceService.ProcessReceipt = ProcessReceipt

Whenevre I buy a product, each time I buy it, the print increases by 1, so i buy something, it prints buy once. I buy a second thing, it prints it twice, etc. Eventually, if I have 100 products purchased, it’s gonna be running the :ProcessReceipt function 100 times in a single buy for some reason…

1 Like

You’re not returning the Enum.ProductPurchaseDecision in the outermost function MarketplaceService.ProcessReceipt. You are returning it within a pcall function.

1 Like

add a debounce.

1 Like

Try disconnecting your data store code from process receipt. Roblox is likely repeat firing the callback due to the call not returning immediately, due to UpdateAsync being a yielding function.