Online payments made easier by Digiryte using Flutter and Ruby on Rails
November 06, 2019 10:30
8 min read228 views so far!
This article explains how to make SCA and PCI compliant card payments using Stripe from mobile applications using Flutter and Ruby on Rails
There are countless articles available for this, yet, most of them do not explain the actual processes that happen when we use the plugin and how to save the cards and charge it the next time. So, I thought it would be of some help to show how I was able to implement it in one of my projects.
Stripe is a payment gateway with lots of useful features such as recurring payments, escrow accounts, and real-time credit card number validation using Luhn’s algorithm. With the introduction of SCA rules in the UK, Stripe also provides SCA compliant API’s and PaymentIntents make your work very simple.
So let’s get started with it.
The first step would be to create an account in Stripe and switch to Test mode. We will be provided with a secret key and a publishable key. Our Flutter application is linked with the stripe account using the publishable key and merchantId provided by Stripe.
For this, we have to add the stripe_payment package to our project. Follow the instructions on the installation page of the package.
Now, let’s set up the connection in the initState() method of your widget.
The above code connects the application with your Stripe account and therefore, all payments made by this app will be received in your account which you can keep track of in the Stripe dashboard.
Adding a new card:
Next, let us create a Credit Card form to accept a new card from the customer.
The paymentRequestWithCardForm()methodtakes in an argument of type CardFormPaymentRequest(). You can create an object ofCardFormPaymentRequestand pass it to the function if you wish to add a billing address. This method creates a native view of the credit card details page in IOS and Android as follows:
Validation of the card:
The Credit Card number field is validated using Luhn’s algorithm in real-time and also the card type is detected automatically using regular expressions by Stripe. So, we don’t have to worry about the authenticity of the card number. If the user’s card is not supported in a particular geographical region, Stripe handles that and declines the card automatically with an error message. More importantly, Stripe does not save your Credit card number or CVC. It follows a tokenizationalgorithm to securely save the details of your card which can be reused later by the user.
Once your card is valid and has been accepted, stripe creates an object of type PaymentMethod which includes the expiry date of the card, the last 4 digits(an object of type Card contains this information) and of course, a payment method id. The payment method id will be used for saving the cards which we will see in the upcoming steps.
Once you have received the paymentMethod object, you can create a new Customer in Stripe for that particular user. Since this part is mostly handled in the server-side, we will just be passing the payment method’s id to the back end.
Once, you receive the paymentMethod id in the server-side, you can create a new Customer and attach this id to that Customer.
Integration with Rails:
The first step in Rails would be the installation of ‘stripe’ gem into your application.
Then your controller needs to be configured with the test secret key provided in your Stripe account.
Creating a new customer:
Now, let’s create a Stripe customer and then attach the payment method that is returned by the client-side to the customer.
The customer object is used for tracking multiple payments associated with the same customer. The above code snippet creates a customer with their email and the payment method is attached to the customer object (For additional attributes in Stripe customer creation, refer to the Stripe documentation).
Creating a paymentintemt:
Once a customer object is created, you can create a PaymentIntent. PaymentIntentobject is created to simplify the complexity of asynchronous payment flow by keeping track of the lifecycle of the checkout initiated by the customer. For each transaction, exactly one payment intent is created.
Here confirmation_method can be automatic or manual. Automatic confirmation method is handled by the publishable key and is used when the payment intent is confirmed on the client-side. Manual confirmation method is handled by the secret key and the payment intent status results in either ‘requires_confirmation’ or ‘requires_action’ after the next actions are performed.
If the status of the intent is requires_confirmation, the payment is confirmed automatically since we provide explicit confirmation using the confirm attribute. Then the status is changed to succeeded and the after payment logic is handled if necessary.
If the status of the intent is requires_action, then the client_secret in the paymentIntent object is returned to the client-side to perform authentication.
After the authentication is performed by the client-side, the status of the payment intent changes to requires_confirmation. Then the payment intent is confirmed using the id of the intent returned from the client-side. After confirmation, the status is changed to ‘succeeded’ and the after payment logic is handled if necessary.
Note: The PaymentIntent can be created and confirmed in the client-side also using the curl command and confirmPaymentIntent() method(refer the official Stripe documentation). But since we’re using a database to store the transaction details, I just preferred doing it in the server-side.
Authenticating a payment intent:
After receiving the client_secret of the paymentIntent from the server-side, we can authenticate the paymentIntent from the client-side using the authenticatePaymentIntent() method.
And voila!!! We have successfully made our first payment using Stripe.
Saving and Reusing cards:
Now there is the question of how to save these cards used by the customer for future transactions. Stripe makes it extremely easy to do this. Remember how you added the PaymentMethod to the Customer? The Card object in the PaymentMethod object consists of the card details along with a unique fingerprint for each card based on the Card number. So, we just have to save the payment method in the Customer object and whenever we want to display the saved card details, just fetch the payment methods attached to that customer and return the card objects.
The PaymentIntents can be created with any of these existing PaymentMethod ids. The Payment Intent just uses the card information provided in the PaymentMethod id using which it was created and therefore, that same card will be charged. So instead of creating a PaymentMethod, we just pass the existing PaymentMethod id to the server-side.
For charging the existing customer, we need the customer id returned by the stripe customer object at the time of creation. So, let’s store the stripe customer id in the database along with the unique user id. Already existing customers can be retrieved using the following code snippet.
Retrieving saved cards:
If the customer already exists, there is a possibility of two payment methods: one is adding a new card and the other, using the already existing card. We shall use the fingerprint attached to the card in each PaymentMethod to retrieve the existing cards. Note that the fingerprint for each card is unique. If the fingerprint already exists, just create a PaymentIntent using the existing PaymentMethod. If a new card is added, the existing fingerprint check using the PaymentMethod will fail. So, first, attach the PaymentMethod to the retrieved customer and create the payment intent with the given PaymentMethod for the completion of the payment.
A new PaymentIntent is created using @payment_method_id for each transaction and the client_secret in the PaymentIntent object is passed to the client-side.
In this way, we can just keep charging the existing card by using the payment method only. To show the details of your purchase, I have created a Ticket Widget in Flutter. Kindly check that out too.
By following the above methods, the whole online payment method is simplified and Digiryte, being one of the first companies to embrace Flutter, we have the right technology and innovation to make your idea a grand success at all stages of growth.