Accepting payments with Stripe and ASP.NET Core

Stripe is a service for doing online payments. It's easy to get started with it because they take care of both the frontend and the backend. The frontend scripting is available for many different frameworks like React, Android, IOS and of course JavaScript and with different levels of customization. The backend is also available in almost any backend framework one could wish for, like .NET. We will discuss the different options for a JavaScript frontend, the .NET package for Stripe as the title suggests, and lastly, the use of Webhooks.

Choosing a frontend option

The frontend uses tokens to represent the card’s information. It does so by preventing the default submission of the form and creating a token of the card’s information by contacting the Stripe servers. This ensures you never need to handle personal card information on your server. It is recommended to use a SSL certificate on the payment site to ensure no one can intercept the information that the client script sends.

Stripe.js is the most basic and lightweight option and the one most customizable. It supplies a clean multipart input where the user can fill in their card nr., expiration date and CVC nr. The input instantly detects the card type and validates of the card nr. and expiration date. You can read more about the integration of Stripe.js in Stripe's guide.

Example of simple Stripe.js form

Checkout gets you all you need to make an easy payment form. It is shown as an overlaying form on your website, which is triggered by a button press. The form includes an email field, an option to remember the card information and a multipart input equivalent to the one described for Stripe.js. It is possible to customize the form somewhat and even make custom handlers for interacting with the form. The newest version of Checkout also makes it possible to use 3D Secure. You can read more about the different options for integration of Checkout in Stripe's guide.

Secure payments

From the 4th of September 2019 new security standards will apply for online payments in the EU. So, if you are targeting an European or global customer segment, you should have this in mind. The EU council PSD2 continuously work on making online payment safer for the users. This requires payments to be done using an extra step of security. You have probably already seen such methods and the one most popularly used by different banks is 3D Secure. This is already an integrated part of the Checkout solution, but is not a supported feature in Stripe.js without performing some extra steps. To enable this for Stripe.js you will need to use a PaymentIntent.

Registering at

Before getting started with coding you need an account at Stripe. You get this by going to their register page and filling out the form. After you are done with this you can access the Stripe dashboard. A nice feature that we will need in this experimental test phase is the View test data, which you can enable/disable directly in the menu. This option switches between real and test payments, API keys and so on. To see and create API keys go to Developers>API keys. You have both publishable and secret keys, but you should never use the secret key on the frontend. These keys differ depending on if you are in testing mode or not, so make sure to switch to live keys when you publish your site.

The main menu in the Stripe dashboard

Creating a payment

We chose to use MVC in our example and have made a Controller for payments and associated views. We chose to use the Checkout for our frontend, because it has the simplest setup.

    ViewData["Title"] = "Payment";

    <form action="/Payment/Processing" method="POST">
        <script src="" class="stripe-button"
                data-name="[My Company Name]"
                data-description="10 rubberducks for 1$ each"
                data-label="Pay 10$">

The elements in the form are made by the referenced JavaScript, so this is all you need for the frontend for now. You can change the form to your liking by using the data attributes. An example could be to fill out the amount dynamically using a ViewModel or ViewBag as shown. Other options such as specifying the currency (US Dollars is the default) can be added as well and you can read more about this in Stripe's guide for Checkout. On submit, the form posts the inputs to the action specified, which include the strings stripeToken and stripeEmail by default. Stripe.js also creates the input named stripeToken on submit, so the frontend can easily be switched to that implementation.

Monitoring errors and uptime on your ASP.NET Core applications?

➡️ for ASP.NET Core ⬅️

To get started on the backend we first need to add the package NuGet to our project. We then need to define the API key that we will use and a good convention is to set this in the Configure-method in Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    //Your other configuration

We refence our API key using User Secrets, but you could use App Settings or an inline string instead, if that fits your style better. You can read more about User Secrets in our post ASP.NET Core (not that secret) User Secrets Explained.

We can now make the controller for our Payment Views and the post:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Stripe;

namespace StripeTest.Controllers
    public class PaymentController : Controller
        private int amount = 100;
        public IActionResult Index()
            ViewBag.PaymentAmount = amount;
            return View();

        public IActionResult Processing(string stripeToken, string stripeEmail)
            Dictionary<string, string> Metadata = new Dictionary<string, string>();
            Metadata.Add("Product", "RubberDuck");
            Metadata.Add("Quantity", "10");
            var options = new ChargeCreateOptions
                Amount = amount,
                Currency = "USD",
                Description = "Buying 10 rubber ducks",
                SourceId = stripeToken,
                ReceiptEmail = stripeEmail,
                Metadata = Metadata
            var service = new ChargeService();
            Charge charge = service.Create(options);
            return View();

We take the two parameters stripeToken and stripeEmail in our action, but could add more, like information about the billing address, if you enable that in the frontend (if you have more inputs than this, a better approach would be to use a model for the form, but for now this should be fine).

We would like to add some metadata to the charge which we will use later. This is done using a Dictionary.

We then create a ChargeCreateOption object which contains the information about the Charge, where we pass in stripeToken and the Metadata Dictionary. We then create a ChargeService and use the ChargeCreateOption to make the charge. The Status of the Charge is at first pending and will change to either succeeded or failed when the charge has been processed by Stripe.

Respond to the payment

But what now? How do we know the Status of the charge? There are two different ways of getting the Status of the charge.

We can Retrieve the charge. This is done using a ChargeService again and using the action .Get(id) which takes the id of the Charge as a parameter, which we would have to save when we create it. The status could still be pending when we make the request, so we would have to run the request multiple times in intervals to check.

We can use Webhooks. In the Dashboard, we can specify an endpoint that will be called when a Charge changes status and use this to take actions on our server when we need to and not make unnecessary requests.

We decide to use Webhooks. We first need to make the Webhook on our page. We simply add another action to our Controller:

private readonly string WebhookSecret = "whsec_OurSigningSecret";

//Previous actions

public IActionResult ChargeChange()
    var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();

        var stripeEvent = EventUtility.ConstructEvent(json,
            Request.Headers["Stripe-Signature"], WebhookSecret, throwOnApiVersionMismatch: true);
        Charge charge = (Charge)stripeEvent.Data.Object;
        switch (charge.Status)
            case "succeeded":
                //This is an example of what to do after a charge is successful
                charge.Metadata.TryGetValue("Product", out string Product);
                charge.Metadata.TryGetValue("Quantity", out string Quantity);
                Database.ReduceStock(Product, Quantity);
            case "failed":
                //Code to execute on a failed charge
    catch (Exception e)
        return BadRequest();
    return Ok();

We have made the Action ChargeChange which starts by reading the body that was passed with the post. We then try to construct the event and cast it to the Charge type. Depending on the Status we can act differently, like updating our stock status for our imaginary web shop.

We also use to ship the possible exception so we have an overview of the errors that happen in this critical part of a site. You can read more about how to do this in our documentation Logging to from ASP.NET Core. An error that one could experience in the start could be an API Version Mismatch since we have chosen to throw an error for these mismatches in the construction of the event.

Now we just need to have Stripe call our Webhook, which is done in the dashboard in the menu Developers>Webhooks and selecting Add endpoint. We then enter the path of our webhook, which would be something like:

We can also choose to have it only access our webhook for certain types of changes, like only when a it changes to charge.succeeded or charge.failed. After this you can go into the Endpoint in the list and see our Webhook Secret.

This is a basic start for how to work with Stripe. They have many more features we didn't get to cover, including the new PaymentIntent and the setup of Subscriptions. It's easy to imagine many more technologies that Stripe could be used together with, like SignalR for real-time response on a status update of a Charge. If you have any questions or critique for this article feel free to reach out to us, and speak your mind. Error logging and Uptime Monitoring for your web apps

This blog post is brought to you by is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.

See how we can help you monitor your website for crashes Monitor your website