Build a Subscription Based Website Using Paystack Subscription API and ASP.Net MVC




The subscription business model is a business model in which a customer must pay a recurring price at regular intervals for access to a product or service.

In this article, I will work you through how I have taken advantage of Paystack Subscription to build a fully functional subscription-based website for my client.


Introduction 

Paystack has grown to become the best payment solution platform in Nigeria - even in the whole of africa. On the developers part, they have got a well documented API with loads of libraries both from the community and from paystack themselves.

Paystack Subscriptions allow customers to pay a specific amount every hour, day, week, month, or year depending on the recurring interval you set. With subscriptions, you only need to initialize the first payment, and Paystack will handle the renewals when they are due.


What we will be building

We will build a subscription-based website for a fictitious company that offers payroll application on subscription basis.

An interested customer will visit the website and choose any plan of their choice, then subscribe to that plan, as from then going forward paystack will take care of debiting the customer when payments are due.

We are going to create a method that will keep listening to webhook in other to intercept all recurring debit.

Steps

  1. Create a plan
  2. Charge the customer but omit the plan in the body parameter
  3. Initiate a subscription payment and pass the customer email and plan
  4. Listen for subscription payments

Let's start the process by following the above process:

Creating Plans

We will create four different plans that suit our app. Below is the pricing page of the website we will be building:

As you can see from the image above, we have four plans with their individual costs. Login to your paystack dashboard, on the side menu click on plans and click on create a plan button. See screenshot below:


As you can see from the screenshot, we need to specify the amount.


Charge the customer but omit the plan in the body parameter

According to the docs on paystack website, if you want to create subscription by calling the create subscription endpoint, you must have charge the customer before as it requires a customer code and authorisation. Hence, I chose to charge the customer with amount of the plan selected without passing the plan parameter to get back customer code and authorisation.

First let me show you the application database table structure and explain what each of them are used for.

Carts

This is used to collect a selected plan details of a customer since they may be new and we dont have their record with us.

Customers

This stores the customer information after payment has been made.

Subscriptions

This is used to store payment histories of our clients both initial payment and also all the renewals.

SubscriberAccounts

This acts as the client account - here we can check for the expiry date to know if the subscriber is still active. Notice that we have subscriptioncode and emailtoken fields, these two are need as they are used to cancel subscription.
Let's move to charging the customer. Since am writing this in .Net I will be making use of .Net Paystack SDK written by me.

And then create a method that will charge the customer. The method look like this:
public async Task InitTransaction()
        {

            var customerDetail = new CustomerViewModel()
            {
                email = Request.Form.Get("cust_email"),
                firstName = Request.Form.Get("cust_fname"),
                lastName = Request.Form.Get("cust_lname"),
                phone = Request.Form.Get("cust_phone")
            };

            var cartCode = Helpers.GetCartId();
            var cartItem = repo.GetCartItem(cartCode);

            var paystackSec_Key = ConfigurationManager.AppSettings["PayStackKey"].ToString();

            var payStackAPI = new PaystackTransaction(paystackSec_Key);

            var amount = (Convert.ToInt32(cartItem.amount) * 100);

            var reqBody = new Paystack.Net.Models.TransactionInitializationRequestModel()
            {
                email = customerDetail.email,
                firstName = customerDetail.firstName,
                lastName = customerDetail.lastName,
                amount = amount
            };

            //Charge Customer

            var initResponse = await payStackAPI.InitializeTransaction(reqBody);

            if (initResponse.status)
            {
                //Create Order and customer
                var custCode = Helpers.GenerateRandomDigitCode(10);

                if (repo.CreateCustomerSubscription(customerDetail.firstName, customerDetail.lastName, customerDetail.email,
                    customerDetail.phone, custCode, cartItem.planName, cartItem.amount, initResponse.data.reference,cartItem.planId))
                {
                    repo.RemoveItemFromCart(cartCode);
                    Response.AddHeader("Access-Control-Allow-Origin", "*");
                    Response.AppendHeader("Access-Control-Allow-Origin", "*");
                    Response.Redirect(initResponse.data.authorization_url);
                }


            }
            
            return View("OrderError");




        }


This method will be called whenever a customer select any of the plans, dont forget that we have added the plan code copied from our paystack dashboard after creating the plans.

Initiate a subscription payment and pass the customer email and plan


Now we need a way of creating subscription for the customer after a successful payment. So to do this I chose my callback url method to do this. Below is the code I use in creating the subscription:
[Route("paystatus/check")]
        public async Task PaymentCallBack()
        {
            var tranxRef = HttpContext.Request.QueryString["reference"];

            if (!string.IsNullOrWhiteSpace(tranxRef))
            {
                var paystackSec_Key = ConfigurationManager.AppSettings["PayStackKey"].ToString();
                var payStackAPI = new PaystackTransaction(paystackSec_Key);
                var response = await payStackAPI.VerifyTransaction(tranxRef);

                if (response.status)
                {
                    var subscriberInfo = repo.GetSubscription(tranxRef);
                    var planId = subscriberInfo.PlanId;
                    var subscriptionStartDate = DateTime.Now.AddMonths(1);
                    var payStckSubscription = new Paystack.Net.SDK.Subscription.PaystackSubscription(paystackSec_Key);
                    var subscriptionResponse = await payStckSubscription.CreateSubscription(response.data.customer.email, planId,
                        response.data.authorization.authorization_code, subscriptionStartDate.ToString("s"));
                    var customer = repo.GetCustomerByEmail(response.data.customer.email);
                    if (subscriptionResponse.status)
                    {
                        var data = subscriptionResponse.data;

                        repo.CreateSubscriberAccount(response.data.customer.email, "password", planId, data.subscription_code, data.email_token, subscriptionStartDate);
                        
                        repo.UpdateSubscription(tranxRef);
                    }
                    

                    return RedirectToAction("Success");
                }
                else
                {
                    return RedirectToAction("error");
                }

            }

            return RedirectToAction("error");
           
        }


As you can see, I am only calling the CreateSubscription of the API after I have checked if I was able to charge the customer.


Listen for subscription payments According to the docs Events are used to track subscriptions. When a subscription is created, a create.subscription event is sent to your webhook URL. To track subscription payments, watch for the charge.success event sent for successful subscriptions.

I created an action that represent my webhook url and the method look like so:
  [RoutePrefix("hook")]
    public class HookController : Controller
    {
        
        [Route("events")]
        public ActionResult Listen()
        {
            var requestBody = Request.InputStream;
            requestBody.Seek(0, System.IO.SeekOrigin.Begin);
            string jsonString = new StreamReader(requestBody).ReadToEnd();

            ChargeEventViewModel eventOjb = null;

            eventOjb = JsonConvert.DeserializeObject(jsonString);

            if (eventOjb.@event == "charge.success")
            {
                //Update subscribers account

            // eventOjb.data contains every information needed
            }

            return null;
        }
    }

As always, the complete source code of this application is available on my github page. Please let me know how you have done yours or you have a better idea on how this can be done especially paystack staff. Happy Coding!.

No comments:

Powered by Blogger.