question

Adam Matheny avatar image
Adam Matheny asked

Requesting Help with implementing Real Money Purchases in Unity C#

While I managed to get Virtual Currency transactions functioning on our project some time ago, I've been having some difficulty with figuring out the proper implementation of the StartPurchase/PayForPurchase/ConfirmPurchase sequence in C# when handling Real Money (RM) transactions.

In this example I'm trying to use Real Money to purchase a catalog item that will grant the user Virtual Currency (VC).

Here's what I have so far:

//Try to purchase the 100 VC pack ~Adam

                #region Start the Purchase
                //Declare the item to purchase ~Adam
                ItemPuchaseRequest itemToPurchase = new ItemPuchaseRequest();
                itemToPurchase.ItemId = "currency_pack_100";
                itemToPurchase.Quantity = 1;

                //Create a request to purchase the item ~adam
                StartPurchaseRequest startRequest = new StartPurchaseRequest(); 
                startRequest.CatalogVersion = items[CurrencyPackNumber].CatalogVersion;
                startRequest.StoreId = "currency_pack_100";
                startRequest.Items[0] = itemToPurchase;

                StartPurchaseResult startResult = new StartPurchaseResult();//ERROR HERE

                PlayFabClientAPI.StartPurchaseCallback startCallback = new PlayFabClientAPI.StartPurchaseCallback(startResult);
                ErrorCallback purchaseErrorCallback = new ErrorCallback((PlayFabError error) => new PlayFabError());
                PlayFabClientAPI.StartPurchase (startRequest,startCallback, purchaseErrorCallback);


                #endregion

                #region Pay for the Purchase
                //Create a request to pay for the item ~Adam
                PayForPurchaseRequest payRequest = new PayForPurchaseRequest();
                payRequest.OrderId = startResult.OrderId;
                payRequest.ProviderName = "PayPal";
                payRequest.Currency = "RM";

// payRequest.Items[0] = itemToPurchase;

                PayForPurchaseResult payResult = new PayForPurchaseResult();//ERROR HERE

                PlayFabClientAPI.PayForPurchaseCallback payCallback = new PlayFabClientAPI.PayForPurchaseCallback(payResult);


                PlayFabClientAPI.PayForPurchase(payRequest,payCallback, purchaseErrorCallback);


                #endregion


                #region Confirm the Purchase
                ConfirmPurchaseRequest confirmRequest = new ConfirmPurchaseRequest();
                confirmRequest.OrderId = startResult.OrderId;

                ConfirmPurchaseResult confirmResult = new ConfirmPurchaseResult();//ERROR HERE

                PlayFabClientAPI.ConfirmPurchaseCallback confirmCallback = new PlayFabClientAPI.ConfirmPurchaseCallback(confirmResult);

                PlayFabClientAPI.ConfirmPurchase (confirmRequest, confirmCallback, purchaseErrorCallback);

                #endregion

I think I mostly have it set up right, but I'm not sure how to properly access the OrderID from the StartPurchase results to use for PayForPurchase and ConfirmPurchase. My current thought was to declare a StartPurchaseResult variable whose OrderId I can reference, but attempting to declare such a variable gives me the following error:

"Expression denotes a 'variable', where a 'type' or 'method group' was expected"

If anyone could please point out where I am going wrong here, it would be greatly appreciated.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

simon avatar image simon commented ·

18 bullet points i need to code manually? Why aren't they all handled for me? Isnt that one of the reasons to have Playfab? Why are payments so over complicated? Everyone wants to do exactly the same thing - send a payment & that changes a variable. No?

0 Likes 0 ·
brendan avatar image brendan simon commented ·

I take it you're referring to the flow with was posted by Adam? He's describing a specific code flow for his game which includes far more than purchasing. Have a look at our commerce tutorials: https://api.playfab.com/docs/tutorials#landing-commerce. The number of API calls required are actually fairly minimal (only one each for any VC purchase, receipt validation, or entitlement check, and at most three for things like Facebook/PayPal/Steam, where we have to set up a "cart" in advance of payment confirmation, and don't necessarily get notified by the payment provider when the purchase is complete).

0 Likes 0 ·
brendan avatar image
brendan answered

Understood - and believe me, if we could replace the rest of the PayPal side of things, we would. :)

Let us know if you run into any trouble when you have that hooked up.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

So, to continue an old line of conversation, I believe I finally got the Paypal portion of our setup implemented, although for now we're just testing with PayPal Sandbox accounts to avoid flinging actual money around before we have all the bugs straightened out.

Our order of operations is now as follows:

When the scene is opened:

1)Get user inventory

2)Request catalog version, and construct catalog/GetCatalogItems

When the button to purchase Currency is pressed:

3)Figure out which item in the catalog the button pressed corresponds to

4)Create an ItemPurchaseRequest and set its ItemID and Quantity

5)Create a StartPurchaseRequest, set its CatalogVersion and StoreID and add the ItemPurchaseRequest created in the previous step

6)Create a StartPurchaseCallback, passing in a custom function called OnStartPurchase()

7)Call the StartPurchase() function, passing in the StartPurchaseRequest and StartPurchaseCallback created in steps 5 and 6. This activates the OnStartPurchase() functinon

In OnStartPurchase():

8)Create a PayForPurchaseRequest and set its OrderID, ProviderName and Currency

9)Create a PayForPurchaseCallback

10)Call the PayForPurchase() function, passing in the PayForPurchaseRequest and PayForPurchaseCallback created in steps 8 and 9

11) Save the StartPurchase result to a variable to use for the OrderID  for the ConfirmPurchase

12) Set PayPal facilitator (seller) credentials to pass to PayPal

13) Open a webpage to the PayPal ExpressCheckout

14) Wait for the user to go through the Express Checkout process on the web page and then hit a "Confirm" button in-game

When the Confirm button is pressed:

15) Get Shipping Details from PayPal

16) Confirm the PayPal payment

15) Call a function called OnConfirmPurchase()

In OnConfirmPurchase():

16)Create a ConfirmPurchaseRequest and set its OrderID using the saved StartPurchaseResult

17)Create a ConfirmPurchaseCallback

18)Call the ConfirmPurchase() function, passing in the ConfirmPurchaseRequest and ConfirmPurchaseCallback created in steps 11 and 12

 

The end result of this is that in the PayPal Sandbox on the PayPal developer dashboard we have notifications that both the facilitator received "payment" and that the buyer received a receipt, but on the PlayFab developer dashboard, it says that the transaction "FailedByProvider".

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Yes, that's because we don't have the PayPal sandbox set up so that you can configure your title to use it as yet. This is on our backlog for a future sprint, but for the StartPurchase flow, we only provide Steam sandbox at the moment. Apologies for the inconvenience. Your logic flow does sound very good, so you should be able to isolate the PayPal testing to your final integration testing.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Adam Matheny avatar image
Adam Matheny answered

Thank you again for taking a look at all of this.  It's been a great help.

Sorry to hear that about the Sandbox support though.  Is there anything you recommend for testing short of passing Real Money back and forth between PayPal accounts that are both owned by team members?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

The account you're sending money to should be your business account, not personal accounts. You can do the majority of the testing without this, and we do apologize for the inconvenience - we'll have sandbox purchasing available as soon as we can.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

ottolb avatar image
ottolb answered

Hi @Brendan,

I followed the steps that@Adam Matheny wrote until 10. Then when I call PayForPurchase it returns:

FailedByPaymentProvider -- Failed to instantiate PayPal transaction.

Right now I'm using my personal account and already granted permission to Playfab. Before I tried to use a sandbox account with permissions to billing-facilitator_api1.playfab.com and got:

PlayFab not authorized to perform acctions on given PayPal account.

What do you think is the problem?

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Well, the first thing is that we don't support PayPal sandbox. The sandbox option in the game settings currently is only for Steam - we'll be adding sandbox support for other platforms later on.

Next though, a FailedByPaymentProvider on the call to PayForPurchase would imply that the payment provider rejected the setup of the "cart" for some reason. It's likely the sandbox issue, so if you switch to live, you should be able to get past this.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

info-2 avatar image info-2 commented ·

@Brendan is PayPal sandbox support somewhere on your roadmap yet? It would be really helpful to not send PayPal $0.30 every time doing a test purchase.

0 Likes 0 ·
brendan avatar image brendan info-2 commented ·

We do have backlog items for adding sandbox purchasing options to the other payment providers (that support sandbox), but I'm afraid we don't have a schedule for that as of yet.

0 Likes 0 ·
psilvestre avatar image
psilvestre answered

Sorry @Brendan, I have understood the flow that @Adam Matheny has explained but I have a question: What happen if after call PayForPurchase function and validating purchase in native store (PayPal, Google Play or whatever) it is an invalid order? How could we set the PlayFab order as invalid or something like that? Should I call ConfirmPurchase function to "close" the current opened playFabOrder? But I don't want to give the items to user...?

3 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image brendan commented ·

Unless the payment provider has verified that the purchase is valid, ConfirmPurchase won't give the user anything. The order will be marked as invalid on our side if the payment provider returns that status for it.

0 Likes 0 ·
psilvestre avatar image psilvestre brendan commented ·

@Brendan Ok, so this flow doesn't work for Apple Store and Google Play, right? Should I call directly ValidateIOSReceipt and ValidateGooglePlayPurchase without calling first to StartPurchase, PayForPurchase and after ConfirmPurchase?

0 Likes 0 ·
brendan avatar image brendan psilvestre commented ·

Correct - the StartPurchase flow is for non-receipt purchasing systems. For iTunes and Google Play, you can use their store with our receipt validation API calls.

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.