❀️23
πŸš€11
πŸ¦„9
πŸ”₯6
🌱4
🀯2

πŸ’° Cash Rules Everything Around Me - Integrating Stripe & Next.js

Integrating Stripe into your JavaScript Web App to take payments for your product


Steve Richardson profile picture
Steve RichardsonSenior Software EngineerSep 24, 2024 β€’ 8 min read

You probably like money huh?

Remember when Stripe burst onto the scene? If you don't... well, here is an immersive experience of what it was like inside their office.

Not the first payment processing company to offer a payment gateway as a service, but they knew what developers wanted - to use tech that had big gradient branding even if it sucked.

Stripe wasn't so bad though, they provided an easy to use API and they took care of all of the insane considerations for taking payments in various regions. This made it super easy for Jian-Yang to offer his Hot-dog app all across the world.

Why use Stripe πŸ’Έ

Reasons to use Stripe:

  • Simplicity

  • Global reach

  • Simplicity

  • Security

  • Simplicity

Reasons to not use Stripe:

  • You hate money

That was a short section.

How we do it πŸ€“

We'll demonstrate the integration with Next.js so if you're using a different setup (because you haven't sold your soul to Vercel... yet), the principles remain the same.

Step 1: Install the Necessary Packages

First things first, you'll need the Stripe packages for both your server and client.

ShipNow
1npm install stripe @stripe/stripe-js @stripe/react-stripe-js

Step 2: Set Up Your Stripe Account

Head over to Stripe and set up an account. It's free, and they don't require a blood sample.

Once you're in, navigate to the Developers section to find your API keys.

Step 3: Secure Your API Keys

Create a .env.local file in your project's root directory. This file will keep your secret keys... well, secret.

ShipNow
1STRIPE_SECRET_KEY=sk_test_your_secret_key NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key

Remember, anything prefixed with NEXT_PUBLIC_ will be exposed to the browser. Keep your secret key safe.

Step 4: Initialise Stripe on the Server

Create a utility file to initialise Stripe with your secret key.

ShipNow
1import Stripe from 'stripe';
2
3const apiVersion = "" // Get the most recent version from the Stripe dashboard 
4
5export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? '', { apiVersion });

Step 5: Create an API Route for the Checkout Session

Next.js lets you create API endpoints effortlessly. Let's create an API route to handle the creation of a Stripe Checkout Session.

ShipNow
1// If you're using pages router, then your file might be: pages/api/create-checkout-session.js
2
3import { stripe } from '@/lib/stripe';
4
5export default async function handler(req, res) {
6  if (req.method === 'POST') {
7    try {
8      const session = await stripe.checkout.sessions.create({
9        payment_method_types: ['card'],
10        line_items: [
11          {
12            price: 'price_yeyeyeyeye', // Replace with your price ID
13            quantity: 1,
14          },
15        ],
16        mode: 'payment',
17        success_url: `${req.headers.origin}/payment-success?session_id={CHECKOUT_SESSION_ID}`,
18        cancel_url: `${req.headers.origin}/payment-cancelled`,
19      });
20
21      res.status(200).json({ sessionId: session.id });
22    } catch (err) {
23      res.status(500).json({ error: err.message });
24      console.error(err);
25    }
26  } else {
27    res.setHeader('Allow', 'POST');
28    res.status(405).end('Method Not Allowed');
29  }
30}

You can create a product and its price in your Stripe Dashboard and use the corresponding Price ID in the snippet above. Also, make sure to define the success_url and cancel_url. After the payment, Stripe will redirect the user to these URLs.

Step 6: Create a Checkout Page

Now, let's set up a page where users can click a button to purchase your product.

ShipNow
1import { useState } from 'react';
2import { loadStripe } from '@stripe/stripe-js';
3
4const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);
5
6export default function Checkout() {
7  const [loading, setLoading] = useState(false);
8
9  const handleCheckout = async () => {
10    setLoading(true);
11
12    const response = await fetch('/api/create-checkout-session', {
13      method: 'POST',
14    });
15
16    const { sessionId } = await response.json();
17
18    const stripe = await stripePromise;
19    await stripe.redirectToCheckout({ sessionId });
20    setLoading(false);
21  };
22
23  return (
24    <div>
25      <h1>Every dollar you spend, will be a dollar in my pocket</h1>
26      <button onClick={handleCheckout} disabled={loading}>
27        {loading ? 'Loading...' : 'Buy Now'}
28      </button>
29    </div>
30  );
31}

Step 7: Handle Success and Cancellation

Create success.js and cancelled.js pages to handle the user's journey after checkout.

ShipNow
1// Success page
2
3export default function Success() {
4  return <h1>Payment Successful! Thank you for your purchase.</h1>;
5}
ShipNow
1// Cancel page
2
3export default function Cancelled() {
4  return <h1>Payment Cancelled. Maybe next time!</h1>;
5}

Step 8: Validate the Payment (Optional but Recommended)

After Stripe processes the payment, you should validate the payment on your server to ensure everything is legit.

Create a new API route to retrieve the session details.

ShipNow
1// pages/api/validate-payment.js
2
3import { stripe } from '../../lib/stripe';
4
5export default async function handler(req, res) {
6  const { session_id } = req.query;
7
8  try {
9    const session = await stripe.checkout.sessions.retrieve(session_id);
10
11    if (session.payment_status === 'paid') {
12      // Payment was successful
13      // You can update your database or perform other actions here
14      res.status(200).json({ message: 'Payment verified', session });
15    } else {
16      // Payment not successful
17      res.status(400).json({ message: 'Payment not successful', session });
18    }
19  } catch (err) {
20    res.status(500).json({ error: err.message });
21    console.error(err);
22  }
23}

You can call this API route from your success.js page to confirm the payment.

ShipNow
1// Success page
2
3import { useEffect, useState } from 'react';
4import { useRouter } from 'next/router';
5
6export default function Success() {
7  const router = useRouter();
8  const { session_id } = router.query;
9  const [message, setMessage] = useState('Validating payment...');
10
11  useEffect(() => {
12    if (session_id) {
13      fetch(`/api/validate-payment?session_id=${session_id}`)
14        .then((res) => res.json())
15        .then((data) => {
16          if (data.message === 'Payment verified') {
17            setMessage('Payment Successful! Thank you for your purchase.');
18          } else {
19            setMessage('Payment validation failed.');
20          }
21        })
22        .catch((err) => {
23          console.error(err);
24          setMessage('An error occurred during payment validation.');
25        });
26    }
27  }, [session_id]);
28
29  return <h1>{message}</h1>;
30}

C.R.E.A.M! πŸŽ‰

You just integrated Stripe into your Next.js app. Now you can start making money while you sleep, only to wake up and realise that people only buy your products in your dreams - or was that just me for the longest time?

Soo... That was quite a bit of boilerplate

If reading through all that code made your eyes glaze over, I've got good news for you. We've already done the heavy lifting.

The ShipNow Boost Template: a Next.js template with Stripe (and sooo much more) already integrated. Here's what you get:

  • Pre-integrated Stripe Setup: Start accepting payments immediately.

  • Tailwind CSS Styling: A beautiful design without the headache.

  • Mailgun Integration: For all your email needs.

  • Firebase Backend: Authentication and real-time database included.

  • TypeScript Support: Because type safety is next to godliness.

  • Storyblok headless CMS: This page was made with Storyblok (and the entire site was built on the boost template).

  • and a ton more...

Stop Wasting Time on Boilerplate 🏎

I don't mean to make you squeal with excitement, but if you take a look at this, you'll see just how much time and money you can save by using this template. With our template, you can focus on what really matters – building features that set your product apart.

Final Thoughts

Integrating Stripe with Next.js doesn't have to be a chore. Whether you choose to do it yourself or use our ShipNow Boost Template, the important thing is to get your product to market and start generating revenue.

So go ahead, take the plunge, and may the cash follow.


Want more?

Get notified about new posts and updates. No spam, I promise.
We will never share nor sell your details.

Related Posts

CTA Background

Ready to get started?

Join the ShipNow community today and start shipping your products.

Get started now