The ability to decline Developer Product purchases

As a Roblox developer, it is too hard to decline a Developer Product purchase.

After 72 hours, the purchase will automatically cancel, but often I don’t want to grant a purchase, and I do not want my function to be called for the next 72 hours because of this. Maybe the player’s data isn’t loaded yet. Maybe the ID isn’t purchasable in this server.

As an example of the friction this causes, whenever someone buys a Developer Product, in many cases their data should be saved before the purchase is granted. This is annoying to do, because making a yield call will cause the purchase handler to keep getting called. You currently need to maintain an inventory of all purchase identifiers that are currently being handled to avoid reprocessing the same purchase multiple times.

Not being able to easily save player data after a purchase is made hurts newer developers, and is probably the culprit behind a fair amount of data loss since this is not obvious.

I propose ProductPurchaseDecision.PurchaseDeclined, which would decline the purchase immediately. Additionally, the callback would not be called again with the same purchase ID until a decision is returned, to allow for easy yielding in purchase handlers.


Why would you need to decline a purchase? Shouldn’t you just not prompt it in the first place if you don’t want the player to buy it?


My specific use case is that I want players to be able to bypass player voting and directly pick the map for the next round in my game. Many will try and do this during a short intermission so the situation could occur where many people are looking at the purchase prompt. I could have a lock that stops all players from seeing this prompt whilst another user is looking at the prompt.

However, from a revenue making standpoint, I want multiple people to see the prompt - not all of them will actually click Buy, and if I had a lock on this then actual purchases would be lost to people who look at the prompt for 10 seconds and then click Cancel.

With the addition of PurchaseDeclined, the first person to click ‘Buy’ on the prompt would choose the map and anyone else who clicked buy after would get their purchase declined. Right now these users still have their purchase appear to go through and then refunded a few days later. Thats going to frustrate kids who think they’ve lost their money.

My use case is quite specific but in most cases I’d reckon it would be far better for the end user to see their purchase denied than for it to go through and to not get their item/currency etc. because something failed internally and the dev decided to return ProductPurchaseDecision.NotProcessedYet.


For starter packs and offers shown to new players

Eg for the first purchase the player could can get $10000 in game for R$80 when it’s usually R$100


Your server should be able to prompt the correct purchase though shouldn’t it? Show the r$80 one if they’re new, r$100 if they’re not.

Making failed purchases a standard mechanism in your game is a bad idea. If I went to a game and constantly got purchases denied I’d leave that game because something in the logic and game design has gone wrong if you’re giving me the incorrect product prompt.

The client could prompt themselves to buy the discounted product though, when they should be paying full price


It’s been just under a year, no interest shown from Roblox.

To quote the ancient reply I didn’t have permissions to reply to at the time in case anyone else ever wondered, the server obviously needs to be able to decline purchases because you can’t trust the client or assume that its state is updated to the server’s. Not to mention you generally want to save a player’s data as soon as they make a purchase, and decline if that fails.

Right now, there are two options:

  1. Track each purchase ID and just keep deferring processing for 72 real world hours. Terrible solution. Probably most popular games do not do this.
  2. Assume success in all cases, probably amounting in some small minority of players losing Robux.

If Roblox cared as much about their users as they pretend to, this wouldn’t even need to be changed, it’d have been the original design. However, I am sure they have higher priorities than making sure users spending money get the product they paid for.

1 Like

let me explain why this is needed

an exploiter can prompt purchase anything they want by themselves which means instead of waiting for the merchant to offer something, they can just get the better deal any time they want

of course I can write code to prevent this from happening say, check if the merchant is offering what the player is trying to purchase if so give 1.5x if not then 1x

but it’s such a pain to work with Developer products

generally I don’t care about Exploiters but the problem is even though they are exploiters I can’t just not give them anything for the purchase

and I can’t cancel the purchase otherwise this would be a lot easier

because of this I can’t implement any cleaver monetization designs and I’m only limited to offering mundane products


I don’t understand the points the original post is making and the purpose it serves doesn’t make sense with the term ‘decline.’ A declined purchase is a purchase I would expect to not be processed and for robux to be returned to the user. The real issue here is that Roblox is firing the function again before the previous time it got fired even returned anything. I cannot imagine a single case where that should happen.

However, the ability to actually say no to a purchase would be incredibly useful. Some use cases off the top of my head are:

  • Declining an attempted purchase of an item the user already owns, for whatever reason they may have obtained it between opening the purchase prompt and making their purchase
  • Declining in the case of two players attempting to gift the same thing to someone - only accepting the first one
  • Declining purchases that happen later than they were meant to be possible - users are able to open the prompt and leave it open for any amount of time resulting in a late attempted purchase

This is necessary for a good user experience as well as for the developer’s monetization. Forcing users’ robux to spend any time at all out of their account would easily cause them to believe their robux was lost and possibly that they just got scammed by the game they’re playing. Declining a purchase could inform the player immediately in-game that they were not charged, as well as returning their robux which they may then choose to spend on something else in your experience.


Hello. I’ve run into the need for this today.

My experience has a system where players can spend a few Robux to cause a small event to happen, upon which no one else can buy any event for a short amount of time while the current event is happening.
Right now, it is entirely possible that two players will prompt the purchase of an event at the same time (before anyone has purchased something thus disabling the ability to purchase), causing one person to potentially try to purchase it after the other already purchased it, and resulting in their Robux being taken unfairly (for a few days).

I can of course return NotProcessedYet, but this is horrible for UX given that I have to somehow explain to the user that their purchase was technically declined due to the current game conditions and their Robux will be refunded eventually. A way to mark the purchase as declined (thus achieving the same result as the user clicking Cancel, no Robux spent at all) is needed for my usecase.


After reading all of this, I still don’t understand how this is an issue? Why would you have the client prompt for a purchase and not the server? That seems to solve the exploit issue right away?
As for multiple clients buying, everything in Roblox is frame stepped, there is no way that two clients could ever time a button press and process to happen at exactly the same time in computer time I mean, down to the microseconds. Even if you script something like this to happen for testing, one still has to happen before the other. If two clients are buying “make it rain” and by the gods of RNG get it to process two purchases at the exact same time, the server could still queue the purchase so that one happens after the other.
It really sounds like a solution looking for a problem to me? :worried:

Please watch the video below. I tried to explain the issue how I see it, and why alternatives don’t really work well:

Apologies if my speech isn’t clear or is hard to understand.

Should a purchase return NotProcessedYet, Roblox will tell the player their purchase went through and continually attempt to process the receipt over the next 72 hours, finally refunding Robux after 3 days should it never return PurchaseGranted. To ensure this happens, you have to put the receipt ID in a Datastore or something similar and return NotProcessedYet every time Roblox attempts to process it. It’d be much simpler for developers (and better for players!) if we were able to just deny it compared to this.

Ok, I understand better now. While I understand how this would be helpful in your example above, I still have to fall back on the developer to plan for something like this. Just like a developer puts an “anti-bounce” function into their game to prevent players from double-firing weapons or double-jumping, this issue would fall under the same category. I already do this in my games for this exact same reason just didn’t realize it related to this topic.

The first player to start the market window should automatically flag the server to not let anyone else open that purchase window until the other user has finished. While I see the benefit of what is being requested, the queue system solution makes more sense from a game design perspective. To each their own of course, if they implement this, I won’t complain. :smiley:

1 Like

One idea is: you can get the players to purchase in-game currency, such as coins. And witht hat currency, they can buy thevote thingy. If someone else beats them to the punch, you can hide the prompt and forget about it.

Only issue is, you have to keep track of the player’s currency yourself via datastores, rather than Roblox hosting it for you.

1 Like