Add MarketplaceService:BindToReceipt and deprecate MarketplaceService.ProcessReceipt

We just had a pretty neat feature completed that’s currently awaiting release:

ProcessReceipt suffers from the same problem as OnClose, and purchase handling is used more often than OnClose, so the issue when it comes to the former is even more severe. You can’t sell products across multiple scripts because setting ProcessReceipt in one overwrites all the others. It’d be great if ProcessReceipt could be given similar treatment to OnClose.

4 Likes

I feel like the correct API to resolve this is not “BindToReceipt” but rather a callback argument to the function that actually prompts the user to purchase.

2 Likes

That may cause some inconsistency though, because you can call the prompt methods locally. So unless the callback version becomes a different method, the same prompt method would have to have different parameter lists on the client/server which doesn’t seem right.

I’m not very familiar with purchasing APIs :frowning: So - not sure a local call is even a good idea! (is it?)

Even if it is, BindToReceipt still has weird semantics - we’d have to probably add a name for each request just so that the request is processed by a specific target script?

I don’t think we should implement this. If there are multiple callbacks for handling purchases, we have to add Enum.ProductPurchaseDecision.DeferToOtherCallbacks so callbacks can specify that they aren’t going to handle a purchase. But let’s say a developer forgets to return anything: should the purchase be declined or should we call the next callback? The current behavior of MarketplaceService.ProcessReceipt when no values are returned is to reject the purchase.

The reason we added multiple callback support for DataModel.Close is simple: unrelated parts of the game want to listen to this event. For example, say you’re using a data store wrapper made by another developer and you also want to report to Google Analytics before the game ends. Now you have to somehow combine two callback functions into one, which results in unnecessary coupling of code.

I’d be fine with deprecating ProcessReceipt and getting an alternative that only worked on the server that used a callback as you described.

The purchase CoreGui is local, and the button they probably clicked to request the purchase is local. I want the least amount of latency possible when the player is buying something, so I think being able to call it locally makes sense.

2 Likes

The main problem with OnClose is that third parties (require(id)'d modulescripts) may use it.
Since Dev Products can only be purchased in the same place, a TP module can’t do anything with it.
(unless something like adding a command to see and buy any product)
Third party stuff would never have to handle a dev product.

Only exception would be some kind of API specifically designed for handling developer products (and others).
But in that case, it would be weird to also use ProcessReceipt yourself.

Only real “problem” the single ProcessReceipt brings is people having one script for each dev product.
I’m not sure if that’s because they don’t understand the wiki or just never read it.

1 Like

I usually have a folder on the server for all of the devproducts. Inside of the folder, there is ModuleScripts. The name of the module is the ID of the product, and the module itself returns a function which is called when a player purchases it
i.e

return function (Player, Save, Receipt)
if theyGotWhatTheyPaidFor then
return true
end
end

This way, all of the devproducts aren’t mashed up into one code block.