MarketplaceService ProcessReceipt not being called?

I have recently been working on monetizing my game. One of the ways which I have decided to do this is though the use of gamepasses. Since this my first time actually working with gamepasses, I have concluded I must be doing something wrong.


The Problem: I have set MarketplaceService.ProcessReceipt to a callback function, however, when a gamepass is purchased, the callback is not being called.
Here is the relevant code (from a ModuleScript called GamepassService in ServerScriptService - yes, I know GamePassService is a thing, but has nothing to do with this):

local MarketplaceService = game:GetService("MarketplaceService")

local Service = {}

-- Table of Gamepass Name : Gamepass ID
local Gamepasses = {
    ["Hotair Balloon"] = 123456, -- obviously I have the real gamepass IDs here
    ["Ferris Wheel"  ] = 123457,
    ["Zipline"       ] = 123458
}

-- Table that stores which gamepasses a player has under their UserId
local PlayerGamepasses = {}

-- Loads player's gamepasses
-- This function works
function Service.LoadPlayer(player)
{
    local gamepasses = {}
    for name, id in pairs(Gamepasses) do
        if MarketplaceService:UserOwnsGamePassAsync(player.UserId, id) then
            table.insert(gamepasses, name)
        end
    end
    PlayerGamepasses[player.UserId] = gamepasses
}

-- Checks whether the player has the gamepass (specified by name)
-- This function works
function Service.HasGamepass(player, gamepass)
    -- ~= nil makes it return a boolean instead of an index if the gamepass is found
    return table.find(PlayerGamepasses[player.UserId], gamepass) ~= nil 
end

-- Isn't being called
Marketplace.ProcessReceipt = function(receipt)
    prints("Running ProcessReceipt...") -- never prints
    print(receipt.ProductId) -- never prints
    
    local gamepass
    for name, id in pairs(Gamepasses) do
        if receipt.ProductId == id then
            gamepass = name
            break
        end
    end

    if gamepass then
        table.insert(PlayerGamepasses[receipt.PlayerId], gamepass)
        print("Added gamepass: " .. gamepass)
        return Enum.ProductPurchaseDecision.PurchaseGranted
    end
end

return Service

For some reason after I purchased gamepasses in studio, the ProcessReceipt callback was not being called. I know this from the fact that nothing was being printed. I have checked all scripts in game to check ProcessReceipt is not being reset to something else (using Ctrl + Shift + f), and it isn’t being set anywhere else. I have also tried added a wait(5) before I set the callback in case any other script is doing it (despite not being able to find where it says so), however this didn’t do anything either. I wasn’t sure if it was just in studio, so I published the place and tested it in the real game (ending up in myself wasting a large portion of my robux - yes I should have made the gamepasses 1R$ each before hand, but I didn’t think of it). In the real game, the same thing happened: ProcessReceipt was not being called.

Just to test that this wasn’t a game-specific bug, I opened up a new Baseplate in Studio and created a gamepass for it. In the Baseplate place, the ProcessReceipt callback was not called either. Please could someone tell me if I am doing something wrong? I have searched on the forums and the docs already, but haven’t found anything useful.

Many thanks

ProcessReceipt is for developer products. For game passes, use MarketplaceService.PromptGamePassPurchaseFinished

4 Likes

Ah, thank you this makes a lot more sense :smiley:

Since this is still one of the highest results on google, do NOT use this.
This function has a vulnerability, same goes for MarketplaceService.PromptProductPurchaseFinished.

Anyone can fake a purchase, so only use this function on the client if you need it.

So stick to ProcessReceipt.

PromptGamePassPurchaseFinished bought arg cannot be spoofed however PromptGamePassPurchaseFinished can be fired multiple times by the attacker, if the attacker does not own the gamepass then it will return false (for the bought arg), For Developer Products, the creator docs literary says to use ProcessReceipt, by the way ive tested such via using RbxStu v4/such.

Creator docs regarding PromptProductPurchaseFinished which says to use ProcessReceipt:

ProcessReceipt is only for Developer Products.