How to manage stripe payments between a connected account and a customer with xamarin forms

Photo by Sophie Dupau on Unsplash

Stripe is the leader in the online payment platform. It provides android and ios sdk.

I have some friends during my holidays who asked me for some help on stripe integration in Xamarin Forms. Not the easiest thing to assess because nothing exists. In my approach, I wanted to propose the user to pay with a new card or registered card.

It exists some solutions with custom bindings but the solutions are not updated and it implies managing both projects ios and android.

Then I investigated to find a good solution to:

Evolve when the stripe solution will be updated

Easy to develop and maintain (sharedproject)

Easy design

Keep compliance: I could not create my own form with Xamarin Forms

I then found a lot of different solutions and I decided to choose the js elements stripe in a webview.

From the stripe website:

Stripe.js is our foundational JavaScript library for building payment flows. The primary integration path through Stripe.js is with Stripe Elements, which enables you to collect sensitive payment information using customizable UI components. Stripe.js also provides a single interface for Apple Pay, Google Pay, and the Payment Request API.

With Stripe.js, you can also tokenize sensitive information, integrate with Stripe Checkout, and handle 3D Secure authentication. Because all sensitive information is handled by Stripe.js, it features simple PCI compliance with SAQ A reporting.

It’s perfectly what I was looking for. In this article, I am going to show you how you can do it easily.

Step1: Create a payment intent

In the stripe approach, you first need to create a payment intent with the details of the payment before creating the payment transaction. It’s a security where the payment intent collects the details of the customer.

Firstly, I generate the payment intent id from the server-side.

public async Task<string> CreatePaymentIntent(StripePaymentInput createRequest){var service = new PaymentIntentService();var createOptions = new PaymentIntentCreateOptions{PaymentMethodTypes = new List<string>{"card",},Metadata = new Dictionary<string, string> { { "from", user.Id.ToString()}, { "to", AIdUser.Heros.Id.ToString() } },Customer = user.CustomerStripeId,Amount = CalculateOrderAmount(createRequest.Price),Currency = createRequest.Currency,TransferData = new PaymentIntentTransferDataOptions{Destination = AIdUser.Heros.StripeAccountId},};PaymentIntent paymentIntent = service.Create(createOptions);return paymentIntent.ClientSecret;}

Tip: I added metadata with an id of my users to be able to look up users in my database when I will have a webhook payment succeed or payment failed

Step 2: Manage the payment

Once I receive my payment intent id from the server I can create my payment.

The goal here is to generate an HTML page with elements and with the payment intent id and other variables.

I needed to manage two cases:

. Pay with a new card

. Pay with a registered card

Both are working with the same mechanism. I create the HTML skeleton and store it as embedded resources in my shared project.

the two HTML files embedded

I took one example of these and customized it:

Tip: To pass parameters and manage translations of the texts I create a function that replaces keys with the value I pass to the HTML file.

In my HTML file for example I will have this line: var stripe = Stripe(‘{{stripeKey}}’);

And I will replace {{xxx}} by the value.

The c# function to load the HTML file and replace values

public async Task<string> GenerateCardKnownAsync(double amount, int herosId, string id, string paymentIntentId){string card = null;string htmlFile = "";string constPath = "****.Html.webpayknown.html";var assembly = Assembly.GetExecutingAssembly();using (Stream stream = assembly.GetManifestResourceStream(constPath))using (StreamReader reader = new StreamReader(stream)){htmlFile = reader.ReadToEnd();}
htmlFile = ReplaceKey("stripeKey", Mobile.App.AppSettings.StripeKeyApi, htmlFile);htmlFile = ReplaceKey("clientSecretPaymentIntent", paymentIntentId, htmlFile);card = htmlFile;return card;}

I am sure there are better ways to do it but this method is easy to manage.

To show it in the app I use a webview and use an HtmlWebViewSource to load my HTML code modified.

On my content page when I load it, I load all the cards which are linked to the user.

Every time I select a card I will load the HTML code generated. I defined an enum where the first card is empty and will represent the entry of a new card.

If the enum value is new then I will load the web HTML and if the enum value is a card with id then I will just show the other HTML.

Once done it will look like this:

Last step: Manage the payment status

Once the UI is fine and the payment process is good, you need to be notified of the payment status.

First, you will be able to receive a webhook, and based on the results you will be able to do some actions.

In my case, I will store the transaction amount, status, and who paid who in my database.

The code in my webhook is as below:

[HttpPost]public async Task<IActionResult> WebHooks(){var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();try{var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], _stripeConfiguration.WebhookSecret);if(stripeEvent.Type == Events.PaymentIntentSucceeded){_stripeManager.HandlePaymentStatus(PaymentStatus.Succeeded,   stripeEvent.Data.Object as PaymentIntent);}else if (stripeEvent.Type == Events.PaymentIntentPaymentFailed){_stripeManager.HandlePaymentStatus(PaymentStatus.Failed, stripeEvent.Data.Object as PaymentIntent);}else if (stripeEvent.Type == Events.PaymentIntentCanceled){_stripeManager.HandlePaymentStatus(PaymentStatus.Canceled, stripeEvent.Data.Object as PaymentIntent);}return Ok();}catch (StripeException exception){Logger.Error(exception.Message, exception);return BadRequest();}}

And in my method HandlePaymentStatus I will check the metadata I filled before.

Just to check the metadata value:

string rIdStr;string tIdStr;if(!paymentIntent.Metadata.TryGetValue("from", out tIdStr)){throw new UserFriendlyException(L("Transmitter does not exist"));}if (!paymentIntent.Metadata.TryGetValue("to", out rIdStr)){throw new UserFriendlyException(L("Receiver does not exist"));}

Based on the results you will be able to update your database

Tip: The metadata makes it easier to retrieve ids from your own system.

What is complicated is that the webhook will allow us to manage the operations we want to do in the backend.

But if we want to notify the app the payment was a success it’s more tricky. I then found a way to manage this easily.

I leveraged the power of the webview and the method navigated.

What I do is when I use the confirm card method in js and it’s a success, I redirect to an URL I defined.

Then my webview is notified and I can push my success page.

The code is below:


stripe.confirmCardPayment('{{clientSecretPaymentIntent}}', {payment_method: {card: elements[0]}}).then(function (result) {if (result.error) {// Show error to your customer (e.g., insufficient funds)payErrorMessage.innerText = result.error.message;} else {window.location.href = "http://localhost/?success";

c# part

private void wv_Navigated(object sender, WebNavigatedEventArgs e){if(e.Url.StartsWith("http://localhost/?success")){// Push your success content page}}

I have taken some time to find this solution. So I share it because I could not find any articles to explain how to do this.

I hope it will help.