MarketplaceService.PromptProductPurchase not working

MarketplaceService.PromptProductPurchase is not working at my game. Every time I try to click buy, it gives me the “something went wrong and your account hasn’t been charged” error. The developer product IDs are all valid and when I checked the developer console, there’s a HTTP 403 error from a core package script.

Stack trace:

15:21:15 – CorePackages.PurchasePromptImpl.Services.Network:81: MarketplaceService:PerformPurchase() failed because HTTP 0 (HTTP 403)
Stack Begin
Script ‘CorePackages.PurchasePromptImpl.Services.Network’, Line 81
Stack End

Not sure if this is an error on my end or Roblox’s end. Here’s a snippet from the script where it’s calling PromptProductPurchase:

local products = {
	{100, 10, 434671864},
	{1000, 90, 434671924},
	{10000, 850, 434671998},
	{25000, 2000, 434672131},
	{50000, 3750, 434672211},

ProductRemote.OnServerEvent:Connect(function(player, id)
	local product = products[id]
	local id, amount = product[3], product[1]
	MarketplaceService:PromptProductPurchase(player, id, false)
	MarketplaceService.PromptProductPurchaseFinished:Connect(function(userId, productId, value)
		if userId == player.UserId and id == productId and value then 
			player.Data.Credits.Value = player.Data.Credits.Value + amount

Looks like you’re calling PromptProductPurchase with a table (or nil) as the id.

1 Like

I just rewrote the script for this post because I wasn’t the one who scripted it originally and the original one is quite messy and hard to follow. Fixed it so that it corresponds with the original script now.

In my experience, HTTP 403 errors are usually closely linked to team create sessions or disabling studio access to API services in the game settings, which it probably isn’t, but is off by default. So if you are developing in a team create and the product you are trying to sell isn’t yours, you might need to use just the normal PromptPurchase function to handle “affiliate gear sales.” I advise you to look around the MarketplaceService page though, there could be a different function you are looking for.

On a different note, it seems like PromptProductPurchaseFinished is deprecated according to the developer hub:

The site says that that you can use the ProcessReceipt callback instead to process the product and make sure everything is correct.

Usually even for developer products, I use :PromptGamePassPurchase. This has worked for me and I believe :PromptProductPurchase() is for catalog items. I may be completely wrong though.

Indeed you are. Not only is this bad practice, but it’s not an appropriate resolution either.

Game passes are kept on a separate ID system from developer products. You are not supposed to be using PromptGamePassPurchase for non-game pass assets. The same goes for developer products; use PromptProductPurchase.

You need to be using the appropriate prompt function for a specific asset type.


Funny thing; the main problem here is being overlooked. OP is indexing a nil table. Read the code carefully. The problem isn’t actually as complicated as you may think.

local product = products[id]

An index in the products table at the indice id does not exist, because the products table isn’t written properly. It’s an array, not a dictionary.

Fix this by changing your table.

local products = {
    [productId] = amount -- What's the point of the second entry?

ProductRemote.OnServerEvent:Connect(function (player, id)
    -- You don't need this check though, just saying
    if products[id] then
        MarketplaceService:PromptProductPurchase(player, id, false)

You can actually do all of this prompting directly from the client, as a matter of fact. Using a remote to prompt a purchase is ultimately pointless, so you’ll want to consider removing that in the future. Wherever you’re firing the remote, simply replace that with a call to PromptProductPurchase and pass your product id there instead.

Also, like goldenstein said, do not use PromptProductPurchaseFinished to grant purchases. Use ProcessReceipt. Only use PromptProductPurchaseFinished for other use cases you might find, such as modifying a Gui to show that a purchase was finished.


False. If you read the documentation for AllowThirdPartySales, you’d know that you can’t prompt a purchase for products part of another game, regardless of the property’s setting.

For some odd reason the person who scripted the game set the names of the shop buttons as the index number of the products in the table on the server so every time the click event is called, he sent the index to the server and used it to index the product id from the table on the server. That wasn’t the actual problem though, the problem was that the PromptProductPurchaseFinished event was deprecated so I fixed the issue by using ProcessReceipt instead.

What they were probably doing was streamlining the purchase behaviour of each product by making a server request using the shop button’s name. I do this as well, it’s not an uncommon practice. I’ve done it mainly for team Guis.

for _, teamButton in pairs(teams:GetChildren()) do
    teamButton.MouseButton1Click:Connect(function ()

I don’t know how your code worked prior to this though because the prompt being made is invalid. Your original code’s products table doesn’t have numerical indices so trying to index a product by id in the products table should be returning nil.

As for PromptProductPurchaseFinished, it’s not actually deprecated. The reason it’s marked as deprecated is to discoruage developers from using it to detect when purchases have been made, as the proper method for doing so is via ProcessReceipt. PromptProductPurchaseFinished is still a very valid function that you can use, though it’s not entirely necessary when you can also handle such events by firing remotes from ProcessReceipt post-purchase.

1 Like

Okay so I found the issue, turns out the developer products weren’t updated in the game settings which explains the HTTP 403 error since I was trying to get a developer product from a different game. Also, arrays have predefined numerical indices that start at 1 and increment by 1 when a value is either inserted or removed from a table.

1 Like

I’m trying to say something completely different in regards to the indices though.

(slight correction on the above one - numerical indices in reference to your productIds)

Did your developer increment the names of the buttons starting from 1? I find that to be very weird when you can just use the productId as the indice and the data as the value. And again, you can literally just prompt the product from the client - the server doesn’t need to get involved.

Yeah he did which is which is why I thought it was so weird as well. But yeah I already changed the script so that it’s no longer involving the server in calling PromptProductPurchase. Thanks for all your help though I appreciate it