Stripe subscription API example

ASP.NET MVC

Stripe is a payment processing platform for processing online payment methods for internet businesses. Because the API uses an iframe to process card details, you do not have to worry about been PCI complaint.

In a previous blog, I wrote about how to you can take payments from your customers in a secure manner.

This blog will show you have to set-up a subscription service in Stripe that also allows strong customer authentication, which will be a requirement in Europe from the 14th September 2019 as part of PSD2 regulations.

With these new regulations, your customer experience will require a different user experience in the form of 3D secure.

The big issue here is that if your transactions do not follow the new authentication guidelines, your customer's bank may decline the payment.

The code below shows how you can set-up your subscriptions, so let begin.

Controller Code

Below we have the controller code; I will explain what it does later.

public class CreateSubscriptionController : Controller
    {
        public ActionResult CreateCustomer(string stripeToken)
        {
            StripeConfiguration.ApiKey  = "sk_test_****";
            var createCustomer = new CustomerCreateOptions
            {
                Email = "mytestemail1@test.com",
                Description = "Test Sunscription",
                Name = "George Phillipson",
                Source = stripeToken,

                Address = new AddressOptions
                {
                    Line1 = "Address Line 1",
                    City = "City",
                    PostalCode = "Post Code",
                    State = "Tyne Wear",
                    Country = "United Kingdom"
                }
            };

            var service = new CustomerService();
            string custId = service.Create(createCustomer).Id;

            //ADD customer to plan

            var addToSubscriptionPlan = new SubscriptionCreateOptions
            {
                CustomerId = custId,
                Items = new List<SubscriptionItemOption>
                {
                    new SubscriptionItemOption()
                    {
                        PlanId = "plan_FP2rPphVeskDv3",
                        Quantity = 1
                    }
                   
                },
                Expand = new List<string> {"latest_invoice.payment_intent"}
               // TrialFromPlan = true
            };

            var subscriptionService = new SubscriptionService();
            var status = subscriptionService.Create(addToSubscriptionPlan);
            
            if (status.Status == "incomplete")
            {
                Session["PaymentStatus"] = status.LatestInvoice.PaymentIntent.ClientSecret;
            }

            return View("~/Views/Home/About.cshtml");
        }
    }

Javascript code

Below is the javascript code used in this demo

using Web.UI.Controllers
@{
    ViewBag.Title = "About";
    string sessionVal = Convert.ToString(Session["PaymentStatus"]);

    string val;
    if (string.IsNullOrEmpty(sessionVal))
    {
        val = "na";
    }
    else
    {
        val = sessionVal;
    }
}
<h2>@ViewBag.Title.</h2>
<h3>@ViewBag.Message</h3>



@if (val == "na")
{
<p>Setup Subscription.</p>
    <form method="Post" action="@Url.Action("CreateCustomer", "CreateSubscription")" id="frmSubscription" name="frmSubscription">
        <div class="form-group">
            <label for="card-element">
                Credit or debit card
            </label>
            <div id="card-element">
                <!-- A Stripe Element will be inserted here. -->
            </div>
            <!-- Used to display form errors. -->
            <div id="card-errors" role="alert"></div>
        </div>
        <button type="submit" id="card-button" name="card-button" class="btn btn-success">Save</button>
    </form>
    @section stripe {
        <script src="https://js.stripe.com/v3/"></script>
        <script>
            var stripe = Stripe('pk_test_***');
            var cardButton = document.getElementById('card-button');
            var clientSecret = cardButton.dataset.secret;
            $(function () {
                var elements = stripe.elements();

                var style = {
                    base: {
                        color: '#32325d',
                        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
                        fontSmoothing: 'antialiased',
                        fontSize: '16px',
                        '::placeholder': {
                            color: '#aab7c4'
                        }
                    },
                    invalid: {
                        color: '#fa755a',
                        iconColor: '#fa755a'
                    }
                };

                var card = elements.create('card', { style: style });

                // Add an instance of the card Element into the `card-element` <div>.
                card.mount('#card-element');

                // Handle real-time validation errors from the card Element.
                card.addEventListener('change', function (event) {
                    var displayError = document.getElementById('card-errors');
                    if (event.error) {
                        displayError.textContent = event.error.message;
                    } else {
                        displayError.textContent = '';
                    }
                });
                var form = document.getElementById('frmSubscription');
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    stripe.createToken(card).then(function (result) {
                        if (result.error) {
                            // Inform the user if there was an error.
                            var errorElement = document.getElementById('card-errors');
                            errorElement.textContent = result.error.message;
                        } else {
                            // Send the token to the server.
                            stripeTokenHandler(result.token);
                        }
                    });
                });
                // Submit the form with the token ID.
                function stripeTokenHandler(token) {
                    // Insert the token ID into the form so it gets submitted to the server
                    var form = document.getElementById('frmSubscription');
                    var hiddenInput = document.createElement('input');
                    hiddenInput.setAttribute('type', 'hidden');
                    hiddenInput.setAttribute('name', 'stripeToken');
                    hiddenInput.setAttribute('value', token.id);
                    form.appendChild(hiddenInput);

                    // Submit the form
                    form.submit();
                }
            });
        </script>

    }
}
else
{
    <h1>3d Secure Required</h1>
    <form method="Post" action="@Url.Action("CreateCustomer", "CreateSubscription")" id="frmSubscription" name="frmSubscription">
        <div class="form-group">
            <label for="card-element">
                Credit or debit card
            </label>
            <div id="card-element">
                <!-- A Stripe Element will be inserted here. -->
            </div>
            <!-- Used to display form errors. -->
            <div id="card-errors" role="alert"></div>
        </div>
        <button type="submit" id="card-button" name="card-button" class="btn btn-success" data-secret="@val">Save</button>
    </form>
    @section stripe {
        <script src="https://js.stripe.com/v3/"></script>
        <script>
            var stripe = Stripe('pk_test_******');
            var cardButton = document.getElementById('card-button');
            var clientSecret = cardButton.dataset.secret;
            $(function() {

                // Create an instance of Elements.
                var elements = stripe.elements();

                // Custom styling can be passed to options when creating an Element.
                var style = {
                    base: {
                        color: '#32325d',
                        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
                        fontSmoothing: 'antialiased',
                        fontSize: '16px',
                        '::placeholder': {
                            color: '#aab7c4'
                        }
                    },
                    invalid: {
                        color: '#fa755a',
                        iconColor: '#fa755a'
                    }
                };

                // Create an instance of the card Element.
                var cardElement = elements.create('card', { style: style });


                // Add an instance of the card Element into the `card-element` <div>.
                cardElement.mount('#card-element');

                // Handle real-time validation errors from the card Element.
                cardElement.addEventListener('change',
                    function(event) {
                        var displayError = document.getElementById('card-errors');
                        if (event.error) {
                            displayError.textContent = event.error.message;
                        } else {
                            displayError.textContent = '';
                        }
                    });
                var form = document.getElementById('frmSubscription');
                form.addEventListener('submit',
                    function(event) {
                        event.preventDefault();
                        stripe.handleCardPayment(clientSecret, cardElement).then(function(result) {
                            if (result.error) {
                                alert("Failed" + " " + result.message);
                            } else {
                                alert("The payment has succeeded. Display a success message.");
                            }
                        });
                    });
            });
        </script>
    }
}

Stripe subscription API example code explanation

In this demo, I have two forms when the page loads I check if Session["PaymentStatus"] is null or empty if it's null or empty I display the subscription form for the customer to enter their details, in this example, I have just hard-coded the values in the controller.

When the form is submitted, I collect the token returned from Stripe and pass it to the controller; this is what makes your site PCI compliant as you are not storing the customer's card details, only the token.

In the controller, I create a new customer and pass the token to the 'CustomerCreateOption.Source', once the customer is created, I retrieve the customer ID from Stripe and the create the subscription, passing in the customer Id created above.

I then create the subscription and then check the status, if the status is incomplete, I retrieve the latest_invoice.payment_intent value, store that in a session and return the page.

I then check for the session value on the page and if it's not null or empty, display the form, this time informing the customer that they need to complete the extra step when the form is submitted, I pass the LatestInvoice.PaymentIntent.ClientSecret value to Stripe along with the customer card details again which triggers the 3D secure pop-up, once done, the subscription is now allowed.

Stripe subscription API example
Subscriptions

Blog Form

 Please complete the required fields (*required)

 *
*