Card payments for our Fintech client
For one of the biggest online lending companies, we were asked to integrate its existing backoffice application with credit card payment providers.
While the customers had the possibility to make payments with cash transfer, it was quite slow and caused issues that involved backoffice staff. The plan was to add a more convenient way of making payments that runs quicker and is less error-prone. The solution should not absorb the company staff like before - when manual interventions and frequent calls with frustrated clients were required to fix issues.
The backoffice application served as a base for a couple of products that were deployed in many countries. We have been engaged in development and deployment of services for Spain, Denmark and Poland.
The application we were going to integrate with was the main system supporting our client's core business: from creating a loan application, through its acceptance, money withdrawal, to full repayment and closing the loan. It was a monolith with a quite big code base maintained and developed by tens of developers. A deployment of such large system was very complicated. Each attempt took a significant amount of time. It was hard to synchronize all the changes that should be applied. Needless to say, the more changes from such a big code base was deployed at once, the more frequently issues of all types arose. As a result, it was neither elastic nor easy to provide a new version of the application.
We have started with integration of DIBS and Mymoid payment providers in Denmark and Spain, respectively. Both were designed and implemented in a form of a microservice, independent from the monolith. The downtime required to deploy a new version of a service was significantly smaller comparing to the long monolith pauses. Thanks to this architecture model, we achieved more flexible deployments and could react much faster to changes in business requirements.
Each service had four fundamental operations implemented: pay with a card, store a card on payment providers’ side, pay-and-store and reissue a payment with the stored credit card. Apart from differences between providers’ APIs, the flow in both services was the same.
After finishing the integration with these two card providers, we have taken care of yet another adapter, this time it was the Worldpay payment processing service. Similar operations to the ones above were implemented here as well. This meant we had three very similar microservices, carrying out the same scenarios with the only difference of using various APIs of payment providers.
Payment gateway idea
So, the idea to unify these services emerged shortly and we have introduced a new one - a generic payment gateway allowing to integrate with various credit card payments providers. We designed a unified API for all currently supported operations. The service handled card payment processing and cooperation with the monolith application. It provided an abstraction layer over a card payment provider adapter.
With such solution, we gained an easy way to set up a concrete adapter implementation. All three existing adapter services became significantly thinner and their only responsibility was to communicate with external providers.
Another useful feature was that the gateway had a possibility to cooperate with several pre-configured adapter microservices. This feature was really important from the business point of view. In case of any malfunction of currently used payment provider, the gateway service could be easily switched to use another one, significantly improving the system’s quality of service. Moreover, we could add business logic that - in some circumstances - could select a payment provider based on its characteristics, i.e. cost of an operation, speed of a given transaction or any other criteria.
Apart from payment gateway, we have implemented two additional features: the possibility to use already stored cards to automatically pay installments on their due date, and sending notifications to customers when their stored cards’ expiration date was approaching. Both were delivered as separate microservices too.
Make payments automatically
The auto-repayments service was cooperating with the monolith application, asking it for a list of installments to be paid on a given day. Next, the service made all payments with the payment gateway service. At the end of processing, the results of operations were reported to the monolith.
The less manual requests from clients the more time for other tasks for backoffice staff.
What was the gain for our client? Backoffice staff received less requests to handle payments manually, which meant that they could focus on other tasks more efficiently. On the other hand, customers of our client received the possibility to set up automatic payments that released them from the necessity of remembering to make a payment on the due date.
Notify about expiring cards
The other service, with notifications about soon-to-expire credit cards, was communicating with the monolith application only. It queried for a list of credit cards that expire for a pre-configured amount of time and, based on that, created notifications to be sent (in a form of an SMS or an e-mail) by another piece of software.
Thanks to such feature, customers of our client were no longer surprised about unsuccessful payment attempts due to expired card.
I pay by myself
Another thing was providing an option of making a payment directly by customers. They had already used a front-end application, so we made the gateway service accessible from within it.
Since then, customers were able to make payments on their own, without the need to call backoffice staff, give them credit card details, and ask to perform the payment on their behalf.
As a result, not only did we give the customers the possibility to make payments in a very convenient way, but also delivered a solution which can be utilized in different countries with a minimal effort.
The way functionality was divided among various services made it really easy for us to update particular parts of the system. We were independent from the monolith application. We could implement services with the most convenient technologies available. Moreover, we gained higher speed of introducing changes in business logic and react more dynamically to dynamic requirements.
Faster issues solving
In case of any issues, it was straightforward for us to localize the service reporting problems, since we had complete logs and knew exactly which step of the process failed. Additionally, code base of a single service was quite small, allowing us to navigate through the code without much effort. Both resulted in much less time required to react, solve the issue and deploy the fix to production servers.
Of course, the utilization of microservices automatically gave us an easy way to scale out when needed. The only thing we would have to do to handle bigger load was deploying another instance of a given service.
Onboarding new people
The next gain is onboarding of new teammates. Having a clear separation of functional blocks in form of microservices, we could assign a new person to work with a small part of our solution and get acquainted with it gradually.
Encapsulation of services
And last but not least, we had our microservices integrated with the rest of the system through a clearly defined API. This resulted with a smaller impact on separated parts when some changes were made in one of them. This way, it was harder to break something accidentally when introducing new code or changing existing one.
The bottom line
Most of our services were implemented in Java and we used on Spring Boot as the common base of all of them.
Thanks to close cooperation with business people, we were able to react very quickly and introduce appropriate changes in the application logic when needed. The solution we have implemented - working closely with a monolith application but separated from it - made such things extremely easy.
The result of our cooperation is a reliable solution that can be adopted to various requirements and can be deployed to production in a short amount of time. Moreover, with the payment gateway service running, delays in loan repayments were significantly reduced. This also meant increased efficiency of call-center staff responsible for monitoring delayed payments.