Stripe, React and Serverless — Part 1

Stripe, React and Serverless — Part 1

Stripe, React and Serverless — Part 1

In this article series, we will talk about how we integrated Sigmetic with Stripe using React and Serverless.

Here in part 1, we will implement the back-end using Serverless. In part 2 we will integrate the front-end in React using Stripe Elements.

Bear in mind that this can be done in various ways and is dependent on the particular purpose.

For Sigmetic we use a setup that includes:

  • Recurrent payments (i.e. subscription model).

  • AWS Lambda to proxy requests to Stripe using Serverless

  • Collecting payment information in React using Stripe Elements

  • We are using TypeScript on both front-end and back-end.

If you are looking for a similar setup to the above, you probably want to read along 😎

Prerequisites

Create an account on Stripe

The first thing you need to do is creating an account on Stripe. You will need to go through the verification process in order to get your API keys. This may take a day or two.

Setup cloud functions with Serverless

You will need to create a setup for your cloud functions using Serverless. Sigmetic is hosted on AWS and is using Lambdas. But you are free to use whichever cloud provider you prefer that is compatible with Serverless.

See here how to get started.

Overview

There are a set of cases that we need to handle, and for each of these cases, we need a cloud function.

  • Create a customer

  • Create a subscription

  • Handle a subscription (e.g. cancel or continue)

  • Retrieve a subscription

  • Retrieve a payment method

  • Update a payment method

  • Retry payment for an invoice

  • Stripe webhooks

Pheww, sounds like a lot, right? 😩 It’s actually not that bad, once you get into it.

We will explain every case and provide code for setting it up 💪 So stay with us a little longer — you will soon have Stripe up and running!

Cloud functions

Let’s get started creating our serverless back-end. We will go through all the cloud functions first, and then we will integrate the whole thing with the front-end.

Install stripe from NPM

Assuming that you’ve already set up a Serverless project; start by installing stripe from NPM.

npm install stripe

How you structure your folders isn’t highly important, but we created a folder in src/lambdas/stripe/ for all our Stripe functions. Because we’re using TypeScript, we can then reference the transpiled js-files in dist/lambdas/stripe/.

Create API keys

You also need to go to your Stripe dashboard -> Developers -> API keys and create a new set of API keys.

ℹ️ While developing, flick the “view test data” toggle in your Stripe dashboard

For the cloud functions, we will be using the secret key.

Create a customer

Customer objects allow you to perform recurring charges, and to track multiple charges, that are associated with the same customer. The API allows you to create, delete, and update your customers. You can retrieve individual customers as well as a list of all your customers. — Stripe docs

Create a new file src/lambda/stripe/createCustomer.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/createCustomer.ts, let’s start by instantiating Stripe:

Now, this function is going to be invoked on a POST request, so let’s define an interface for our body. We expect the body to carry en email and a username:

Then, let’s define our handler:

That’s it 💪 Deploy your new cloud function and try performing a POST request to the endpoint specified and verify that it creates a new Stripe Customer.

You will be able to see the new customer in your Stripe dashboard -> Customers.

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"email": "[test@test.com](mailto:test@test.com)", "username":"Test McTest"}' \
  [https://your-endpoint/stripe/create-customer](https://your-endpoint/stripe/create-customer)

Create a subscription

Next, you’ll define a function for creating a new subscription. For this, you are going to need a Stripe Product. Go to your Stripe dashboard -> Products -> Add product Once you have created a product, go and get the Price ID of that product. We will be using that for this function.

Create a new file src/lambda/stripe/createSubscription.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/createSubscription.ts, once again we instantiate Stripe:

Specify the interface of the body:

Then, define the handler:

This one, we cannot easily test with a POST request, but we’ll get back to this one later when we integrate the front-end.

Handle a subscription

Typically, you want to provide the customer with the ability to cancel their subscription. The subscription will then end after the end of the current billing period. Meanwhile, the customer has the ability to continue their subscription, and everything will be back to the way it was.

With Stripe, we can simply flag whether the subscription will end after the current billing period.

Create a new file src/lambda/stripe/handleSubscription.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/handleSubscription.ts, once again we instantiate Stripe:

import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '', {
  apiVersion: '2020-03-02',
});

Specify the interface of the body:

Then, define the handler:

This one we can test. Go your Stripe dashboard -> Customers. Click on the customer, and scroll down to the ‘Subscriptions’ section. Click on the subscription and get the ID.

Now deploy your new cloud functions, and make a POST request to your defined endpoint:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"subscriptionID": "THE-ID-YOU-JUST-FOUND", "end": true}' \
  [https://your-endpoint/stripe/handle-subscription](https://your-endpoint/stripe/handle-subscription)

Go back to your customer, and scroll down to the ‘Subscriptions’ section. You should see something like this:

Notice the ‘Cancels Jul 9’ badge

Retrieve a subscription

Lastly, we want to be able to retrieve the full subscription object associated with a given subscription.

Create a new file src/lambda/stripe/retrieveSubscription.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/retrieveSubscription.ts, once again we instantiate Stripe:

Specify the interface of the body:

Then, define the handler:

This one we can also easily test by using the subscription ID as we did just before. After deploying the cloud function, send a POST request to your defined endpoint:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"subscriptionID": "THE-ID-YOU-JUST-FOUND"}' \
  [https://your-endpoint/stripe/retrieve-subscription](https://your-endpoint/stripe/retrieve-subscription)

You should get a detailed subscription object back from Stripe.

Retrieve a payment method

In the same manner, as with a subscription, we also want the ability to retrieve a payment method object from Stripe. In particular, this is useful for showing the customer which credit card is currently being used. E.g. showing the type of card and the last 4 digits.

Create a new file src/lambda/stripe/retrievePaymentMethod.ts

In the file serverless.yml add the function:

https://gist.github.com/Silind/484d9f466607b83ea9a0c9cecb3c662e

In the file src/lambda/stripe/retrievePaymentMethod.ts, instantiate Stripe:

Specify the interface of the body:

Then, define the handler:

In the same way, is with the subscription ID, go and find your customer in the Stripe Dashboard and grab the payment method ID from the payment method.

Deploy the cloud function and make a POST request to the endpoint defined:

curl --header "Content-Type: application/json" \
  --request POST \
  --data '{"paymentMethodID": "THE-ID-YOU-JUST-FOUND"}' \
  [https://your-endpoint/stripe/retrieve-payment-method](https://your-endpoint/stripe/retrieve-payment-method)

You should get a detailed payment method object back from Stripe.

Update a payment method

The customer of your product should be able to update their payment method.

Create a new file src/lambda/stripe/updatePaymentMethod.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/updatePaymentMethod.ts, instantiate Stripe:

Specify the interface of the body:

Then, define the handler:

This one is a bit more difficult to test with a simple POST request, so we will come back to this later.

Retry payment for an invoice

This case is a little more special. Sometimes it happens that a payment method is initially accepted (i.e. the credit card is valid), but when the payment method is attached to the customer, something goes wrong. This could be because the bank denies the process, or due to insufficient funds.

The result will be a failed invoice. Specifically, there is a field on the subscription object: latest_invoice.payment_intent.status that will have the value requires_payment_method.

When this happens, both a customer and a subscription is successfully created in Stripe, so we simply want to have the customer retry the payment with another card.

Create a new file src/lambda/stripe/retryInvoice.ts

In the file serverless.yml add the function:

In the file src/lambda/stripe/retryInvoice.ts, instantiate Stripe:

Specify the interface of the body:

https://gist.github.com/Silind/b5b5230ac08c06c04b36e183a14a59f8

Then, define the handler:

Stripe webhooks

The last thing we need to integrate is Stripe’s webhooks. Stripe’s payment lifecycle is really comprehensive, and Stripe allows you to hook into various of these events.

For Sigmetic, we use only three:

  • invoice.payment_succeeded

  • invoice.payment_failed

  • customer.subscription.deleted

Let’s go and set up these webhooks for Stripe. Go your Stripe dashboard -> Developers -> Webhooks -> Add endpoint. Add your endpoint: https://your-endpoint/stripe/webhooks. Add the three events from the list above.

When created, you can create a Signing secret. We will be using that right below.

Create a new file src/lambda/stripe/webhooks.ts

In the file serverless.yml add the function:

# serverless.yml
stripe-webhooks:
  handler: dist/lambdas/stripe/webhooks.handler
  events:
    - http:
        path: stripe/webhooks
        method: post
  environment:
    STRIPE_SECRET_KEY: PUT-YOUR-SECRET-KEY-HERE
    STRIPE_WEBHOOK_SECRET: PUT-YOUR-SIGNING-SECRET-HERE

In the file src/lambda/stripe/webhooks.ts, instantiate Stripe:

Now let’s create three functions, one for each webhook event. We start with invoice.payment_succeeded.

When a payment has been successfully processed, this event will be fired. At Sigmetic, we want to send a confirmation to the customer with a link the invoice.

We also want to enable their paid functionality.

The invoice.payment_failed is fired when a payment failed to process. In this case, we want to send an email to the customer to notify them.

Finally, the customer.subscription.deleted event is fired when a subscription ends.

Then, we define a small handlerMapping object, so we can quickly look up which of the above functions to use:

Finally, we create the handler:

In the Stripe dashboard under Webhooks, you can send test-events to verify that it works correctly. Try it out 😎

Rounding up

This is basically all we need for our back-end.

Make sure to deploy all these cloud functions to the cloud, and test each endpoint to verify that they are all working correctly.

You may also have noticed a bit of redundancy: We put the full examples of the functions in this article, but you may very well benefit from writing some wrapper functionality to keep it DRY.

Next up is integrating it with the front-end.

Read more about that in part 2.