Accepting Payment with Flutterwave in .Net

ASP.Net Featured

 

Flutterwave allows individuals and businesses to receive payments over the Internet. It’s easy to integrate with different platforms.

Integrating payment solutions via the usage of plugins or libraries could be an overkill in some scenario. For example if all you are not willing to use all the features provided by the payment provider which would probably be part of the library you want to use.

In this article, I will walk you through how you can integrate flutterwave with .net without using any plugin or library.

To get started, first sign up with flutterwave which is a very simple process. Just fill in some basic information and then confirm your email address.

Once you confirm your email address, you will be provided with set of API keys. You will get test and live keys.

Flutterwave Standard

We will be using the flutterwave standard to accept payment in this case. Accepting payment with flutterwave standard can be done in two basic steps:

  • Step 1 – Initialize Payment Transaction
  • Step 2 – Verify the Payment Transaction

To better explain this, let’s start by creating the real .Net project. I will be using .net core project for this but the code will also work for any other .net frameworks

Create the Project

Create a blank solution in visual studio and name it RavePay.

flutterwave payment integration net blank solution add

Add a .net core class library named RavePay.Payment to the blank solution, also add a new webapplication project named RavePay.Web so that the project structure will look like so:

rave payment integration project structure

Let’s focus our attention on the RavePay.Payment class library for now. We will start by creating an extension method for HttpClient, so create a class within the class library named HttpFactory.cs and add the following code.

public static class HttpFactory
    {
        public static HttpClient InitHttpClient(string baseUrl)
        {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
            var client = new HttpClient()
            {
                BaseAddress = new Uri(baseUrl)
            };
            client.DefaultRequestHeaders.Clear();
            return client;
        }
        public static HttpClient AddMediaType(this HttpClient client, string mediaType)
        {
            client.DefaultRequestHeaders.Accept.Add(
               new MediaTypeWithQualityHeaderValue(mediaType));
            return client;
        }
        public static HttpClient AddHeader(this HttpClient client, string headerKey, string headerVal)
        {
            client.DefaultRequestHeaders.Add(headerKey, headerVal);
            return client;
        }
        public static HttpClient AddAuthorizationHeader(this HttpClient client, string authType, string secretKey)
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authType, secretKey);
            return client;
        }
    }

As you can see the code is self explanatory, it contains some chainable methods to build HttpClient that we will be using to make request.

Create Payment Initialization Method

Initializing Payment is done by collecting customer basic and order information, then send to an endpoint. Let’s look at the structure of the request body. The below JSON represent the request body and we need to convert that to C# POCO

{
   "tx_ref":"hooli-tx-1920bbtytty",
   "amount":"100",
   "currency":"NGN",
   "redirect_url":"https://webhook.site/9d0b00ba-9a69-44fa-a43d-a82c33c36fdc",
   "payment_options":"card",
   "meta":{
      "consumer_id":23,
      "consumer_mac":"92a3-912ba-1192a"
   },
   "customer":{
      "email":"user@gmail.com",
      "phonenumber":"080****4528",
      "name":"Yemi Desola"
   },
   "customizations":{
      "title":"Pied Piper Payments",
      "description":"Middleout isn't free. Pay the price",
      "logo":"https://assets.piedpiper.com/logo.png"
   }
}

Let’s convert this JSON to C# class, start by creating a folder named Models and add a class named TransactionInitInputDTO.cs and paste the following code.

 public class TransactionInitInputDTO
    {
        public string tx_ref { get; set; }
        public string amount { get; set; }
        public string currency { get; set; }
        public string redirect_url { get; set; }
        public string payment_options { get; set; }
        public Meta meta { get; set; }
        public Customer customer { get; set; }
        public Customizations customizations { get; set; }
    }
    public class Meta
    {
        public int consumer_id { get; set; }
        public string consumer_mac { get; set; }
    }
    public class Customer
    {
        public string email { get; set; }
        public string phonenumber { get; set; }
        public string name { get; set; }
    }
    public class Customizations
    {
        public string title { get; set; }
        public string description { get; set; }
        public string logo { get; set; }
    }

We also need to have an object that represent the payment initiation response, that is the response object from the request. The response object contains the payment link.

{
   "status":"success",
   "message":"Hosted Link",
   "data":{
      "link":"https://api.flutterwave.com/v3/hosted/pay/f524c1196ffda5556341"
   }
}

Create a class within the model’s folder named TransactionInitResponseDTO.cs and paste the following code.

public class TransactionInitResponseDTO
{
   public string status { get; set; }
   public string message { get; set; }
   public Data data { get; set; }
 }
 public class Data
 {
   public string link { get; set; }
 }

Now that we have created all the DTO needed for payment initiation, let us create the payment initialize method. Create a folder named payments and create a class named RavePayment.cs then paste the following code:

 public class RavePayment
 {
      private readonly string _secretKey;
      public RavePayment(string secretKey)
      {
         this._secretKey = secretKey;
      }
     public async Task<TransactionInitResponseDTO> InitializeTransaction(string tx_ref, string amount,
                                        string redirect_url, string customerEmail, string customerPhone,
                                        string customerName, string payment_options = "card", string currency = "NGN")
        {
            //Build the input model from the paramters           
            var model = new TransactionInitInputDTO()
            {
                amount = amount,
                currency = currency,
                tx_ref = tx_ref,
                customer = new Customer()
                {
                    email = customerEmail,
                    name = customerName,
                    phonenumber = customerPhone
                },
                redirect_url = redirect_url,
                payment_options = payment_options,
                customizations = new Customizations()
                {
                    title = RaveConstant.SITE_TITLE,
                    description = RaveConstant.SITE_DESCRIPTION,
                    logo = RaveConstant.COY_LOGO_URL
                }
            };
            //create httpclient here
            var _client = HttpFactory.InitHttpClient(RaveConstant.BASE_URL)
                      .AddAuthorizationHeader(RaveConstant.AUTHORIZATION_TYPE, _secretKey)
                      .AddMediaType(RaveConstant.REQUEST_MEDIA_TYPE)
                      .AddHeader("cache-control", "no-cache");
            //Build the request body as json
            var jsonObj = JsonSerializer.Serialize(model);
            var content = new StringContent(jsonObj, Encoding.UTF8, RaveConstant.REQUEST_MEDIA_TYPE);
            content.Headers.ContentType = new MediaTypeHeaderValue(RaveConstant.REQUEST_MEDIA_TYPE);
            //send the request
            var response = await _client.PostAsync("payments", content);
            var json = await response.Content.ReadAsStringAsync();
            //Deserialize and send the response
            return JsonSerializer.Deserialize<TransactionInitResponseDTO>(json);
        }
}

The InitializeTransaction method takes some arguments and then the payment initiation request body is built and sent to payments endpoint. You will noticed that we have RaveConstant been referenced within the method. So below is the raveconstant class.

 public static class RaveConstant
    {
        public const string BASE_URL = "https://api.flutterwave.com/v3/";
        public const string SANDBOX_KEY = "FLWSECK_TEST-8a656484da9953747bf96b858b07b8eb-X";
        public const string PRODUCTION_KEY = "Production_key_goes_here";
        public const string AUTHORIZATION_TYPE = "Bearer";
        public const string REQUEST_MEDIA_TYPE = "application/json";
        public const string COY_LOGO_URL = "http://markdevthoughts.net/wp-content/uploads/2020/10/devtlogo.png";
        public const string SITE_TITLE = "MarkDevThoughts";
        public const string SITE_DESCRIPTION = "Pay for C# course";
    }

Create Payment Verification Method

When the user enters their payment details, Flutterwave would validate then charge the card. Once the charge is completed, they redirect back to the redirect_url provided during initialization and the transaction ID (transaction_id), transaction reference (tx_ref) and the transaction status (status) will be appended as query parameters like so:

/tx_ref=ref&transaction_id=30490&status=successful

Payment Verification Response

Below is a sample code to show the structure of the verification response object.

{
  "status": "success",
  "message": "Transaction fetched successfully",
  "data": {
    "id": 1163068,
    "tx_ref": "akhlm-pstmn-blkchrge-xx6",
    "flw_ref": "FLW-M03K-02c21a8095c7e064b8b9714db834080b",
    "device_fingerprint": "N/A",
    "amount": 3000,
    "currency": "NGN",
    "charged_amount": 3000,
    "app_fee": 1000,
    "merchant_fee": 0,
    "processor_response": "Approved",
    "auth_model": "noauth",
    "ip": "pstmn",
    "narration": "Kendrick Graham",
    "status": "successful",
    "payment_type": "card",
    "created_at": "2020-03-11T19:22:07.000Z",
    "account_id": 73362,
    "amount_settled": 2000,
    "card": {
      "first_6digits": "553188",
      "last_4digits": "2950",
      "issuer": " CREDIT",
      "country": "NIGERIA NG",
      "type": "MASTERCARD",
      "token": "flw-t1nf-f9b3bf384cd30d6fca42b6df9d27bd2f-m03k",
      "expiry": "09/22"
    },
    "customer": {
      "id": 252759,
      "name": "Kendrick Graham",
      "phone_number": "0813XXXXXXX",
      "email": "user@example.com",
      "created_at": "2020-01-15T13:26:24.000Z"
    }
  }
}

To create a C# class that will represent the response, add a class named TransactionVerifyResponseDTO.cs within the models folder and paste the following code.

public class TransactionVerifyResponseDTO
    {
        public string status { get; set; }
        public string message { get; set; }
        public VerifyData data { get; set; }
    }
    public class Card
    {
        public string first_6digits { get; set; }
        public string last_4digits { get; set; }
        public string issuer { get; set; }
        public string country { get; set; }
        public string type { get; set; }
        public string token { get; set; }
        public string expiry { get; set; }
    }
    public class VerifyCustomer
    {
        public int id { get; set; }
        public string name { get; set; }
        public string phone_number { get; set; }
        public string email { get; set; }
        public DateTime created_at { get; set; }
    }
    public class VerifyData
    {
        public int id { get; set; }
        public string tx_ref { get; set; }
        public string flw_ref { get; set; }
        public string device_fingerprint { get; set; }
        public decimal amount { get; set; }
        public string currency { get; set; }
        public decimal charged_amount { get; set; }
        public decimal app_fee { get; set; }
        public decimal merchant_fee { get; set; }
        public string processor_response { get; set; }
        public string auth_model { get; set; }
        public string ip { get; set; }
        public string narration { get; set; }
        public string status { get; set; }
        public string payment_type { get; set; }
        public DateTime created_at { get; set; }
        public int account_id { get; set; }
        public decimal amount_settled { get; set; }
        public Card card { get; set; }
        public VerifyCustomer customer { get; set; }
    }

Next is the payment verification method, we will create this method within the RavePayment class.

public async Task<TransactionVerifyResponseDTO> VerifyTransaction(int transaction_id)
        {
            var _client = HttpFactory.InitHttpClient(RaveConstant.BASE_URL)
                     .AddAuthorizationHeader(RaveConstant.AUTHORIZATION_TYPE, _secretKey)
                     .AddMediaType(RaveConstant.REQUEST_MEDIA_TYPE)
                     .AddHeader("cache-control", "no-cache");
            //Send the request
            var response = await _client.GetAsync($"transactions/{transaction_id}/verify");
            var json = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<TransactionVerifyResponseDTO>(json);
        }

The method code is self explanatory, so I wont be making any explanation on it.

At this point, we are ready to accept payment in our asp.net web application. Let’s now focus our attention on the RavePay.Web.

Below is the preview of how the final web application look like.

accepting payment with flutterwave net web application asp net

I will just be providing two action results code for payment initialization and payment verification in this article but wont be going in depth, however, I will be providing the full source code of the app.

[Route("payment/verify")]
        public async Task<IActionResult> verify()
        {
            var tranxRef = Request.Query["tx_ref"];
            var transactionId = Request.Query["transaction_id"];
            var transStatus = Request.Query["status"];
            if (!transStatus.Equals("successful") || string.IsNullOrWhiteSpace(transactionId))
            {
                return RedirectToAction("FailedPayment", "Error", new { area = "" });
            }
            var transaction_id = int.Parse(transactionId);
            var raveScretKey = RaveConstant.SANDBOX_KEY;
            var raveAPI = new RavePayment(raveScretKey);
            var response = await raveAPI.VerifyTransaction(transaction_id);
            if (response.status == "success")
            {
                if (response.data.status == "successful")
                {
                    var update = await _service.UpdateOrder(tranxRef, true);
                    if (update)
                    {
                        return RedirectToAction("PaymentSuccess", "Home", new { area = "" });
                    }
                }
            }
            return RedirectToAction("FailedPayment", "Error", new { area = "" });
        }
        [Route("inittrans")]
        public async Task<IActionResult> TransactionInit([FromBody] CartModel model)
        

As you can see, creating this without any library is better as it wont add any unnecessary dlls which we may not need, and you can also add more features if you so desire.

.

Similar Posts