What's the best way to handle robux purchases?

Hello!
So, I am working on some shop. I am worried about robux purchases though.
Basically, I have 3 categories.
Each category have some items in it (let’s say one category is Cash and it has product 100 cash, 200 cash, etc)
And each category has its own script. This scirpt would run that function:
MarketplaceService.ProcessReceipt = function(receipt)
and after that, with if statement, it would check if receipt.ProductId. In each of those if statements, datastore increments some data and after wait(0.5), it returns PurchaseGranted.
Problem is, that sometimes, data saves and sometimes not.
I was also testing purchases with real robux (not it studio) and when I clicked “Purchase”, I shutdown server as fast as possible. It took my robux, buy I usually didn’t receive what I should.
I also added :Save() on most important things (even in purchase scripts), autosave and save on bind to close (even though DS2 has its own bindToClose event), so I don’t know if that’s good.
I’ve also had some problems with normal data saving. For example, for unknown reason, if I didn’t add “print” function, data didn’t increment. :confused:

So, what are the best solutions? Should i have all 3 categories in one script for ProcessReceipt? How to not take user’s robux if game doesn’t give them the required item? What about on server crash and shutdown?

Thank you so much for your time!

EDIT: I’ve noticed that a user also lose their robux if they purchase something when a server has already shutdown. How to stop that from happening?

One problem could be that GetPlayerFromUserId isn’t getting the player since the game has disconnected them already, if that is to happen the returned value would be nil.

In the event of that happening you should return a ProductPurchaseDecision of NotProcessedYet, then it’ll retry when they rejoin (I believe).


FYI: Having many if statements for ids can be really quite inefficient, I endorse the use of a dictionary with functions inside and keys set to the ids.

Then you can directly index that and run the function, if the I’d isn’t in the dictionary then return NotProcessedYet.

For example:

local Functions =  {
    [123456789] = function(Player)
        --// Code
    end;
}

--// Then in the ProcessReciept
if Functions[RecieptInfo.ProductId] then
    Functions[RecieptInfo.ProductId](Player)
    return Enum.ProductPurchaseDecision.PurchaseGranted
else
    return Enum.ProductPurchaseDecision.NotProcessedYet
end
1 Like

Thank you for the response.
Since I added those categories in one script, it seems that problem isn’t happening (for now).
I’ve also noticed that after a server shuts down and player purchases something, it actually saves once they rejoin!
Note that I still didn’t finish all tests!

1 Like

Don’t have a full response to offer here, but

If you return NotProcessedYet, the game will continually attempt to run the ProcessReceipt function for three days on the player and if PurchaseGranted isn’t returned within that time, then they will receive their money back. Just worth mentioning.

3 Likes