Stripe is a leading payment processing platform that enables businesses to accept online payments with ease. Next.js, a popular framework for building server-rendered React applications, has gained immense popularity due to its performance, scalability, and ease of use.

In this tutorial, we will walk you through the process of integrating Stripe Checkout with a Next.js application to provide a seamless and secure payment experience for your users.

Table of contents

  1. Prerequisites
  2. Install Stripe Dependencies
  3. Configure Stripe API Keys
  4. Create a Stripe Checkout Session
  5. Create a Checkout Component
  6. Integrate the Checkout Component
  7. Create Success and Error Pages
  8. Setting up Stripe Webhook
  9. Conclusion

Prerequisites

Before we begin, make sure you have the following:

  1. A Stripe account (Sign up at Stripe)
  2. Node.js and npm installed on your local machine
  3. A Next.js project set up (You can create one using npx create-next-app)

Install Stripe Dependencies

First, install the required Stripe packages by running the following command in your Next.js project:

npm install stripe micro @stripe/stripe-js @stripe/react-stripe-js

These packages provide the necessary tools to integrate Stripe Checkout into your Next.js application.

Configure Stripe API Keys

After installing the dependencies, head over to your Stripe dashboard and obtain your API keys (both publishable and secret). Create a .env.local file in your project's root directory and add the following:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=<your_publishable_key>
STRIPE_SECRET_KEY=<your_secret_key>

STRIPE_SECRET_KEY=<your_secret_key>Replace <your_publishable_key> and <your_secret_key> with the respective keys from your Stripe dashboard.

Create a Stripe Checkout Session

Now, let's create an API route to handle the creation of a Stripe checkout session. Create a new file pages/api/checkout_sessions.js and add the following code:

import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export default async function handler(req, res) {
  if (req.method === "POST") {
    try {
      const session = await stripe.checkout.sessions.create({
        payment_method_types: ["card"],
        line_items: [
          {
            price_data: {
              currency: "usd",
              product_data: {
                name: "Sample Product",
              },
              unit_amount: 1000,
            },
            quantity: 1,
          },
        ],
        mode: "payment",
        success_url: `${req.headers.origin}/success`,
        cancel_url: `${req.headers.origin}/`,
      });

      res.status(200).json({ sessionId: session.id });
    } catch (err) {
      res.status(500).json({ error: "Error creating checkout session" });
    }
  } else {
    res.setHeader("Allow", "POST");
    res.status(405).end("Method Not Allowed");
  }
}

This code initializes a new Stripe instance using the secret API key and creates a checkout session for a sample product.

Create a Checkout Component

Now that we have our checkout session API, let's create a checkout component to trigger the Stripe Checkout process. Create a new file components/CheckoutButton.js and add the following code:

import { loadStripe } from "@stripe/stripe-js";
import { useRouter } from "next/router";

const stripePromise = loadStripe(
  process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
);

const CheckoutButton = () => {
  const router = useRouter();
  
  const handleCheckout = async () => {
    try {
      const stripe = await stripePromise;
      const response = await fetch("/api/checkout_sessions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
      });

      const { sessionId } = await response.json();
      const { error } = await stripe.redirectToCheckout({
        sessionId,
      });

      if (error) {
        router.push("/error");
      }
    } catch (err) {
      console.error("Error in creating checkout session:", err);
      router.push("/error");
    }
  };
  
  return <button onClick={handleCheckout}>Buy Now</button>;
};

export default CheckoutButton;

This code initializes the Stripe instance using the publishable key and defines a handleCheckout function, which fetches the checkout session from the API and redirects the user to the Stripe Checkout page.

Integrate the Checkout Component

Now, integrate the CheckoutButton component into pages/index.js:

import CheckoutButton from "../components/CheckoutButton";

export default function Home() {
  return (
    <div>
      <h1>Sample Product</h1>
      <p>Price: $10.00</p>
      <CheckoutButton />
    </div>
  );
}

Create Success and Error Pages

Finally, create success and error pages to handle the user experience after the Stripe Checkout process:

pages/success.js:

export default function Success() {
  return (
    <div>
      <h1>Payment Successful!</h1>
      <p>Thank you for your purchase.</p>
    </div>
  );
}

pages/error.js:

export default function Error() {
  return (
    <div className="container">
      <h1>Payment Failed</h1>
      <p>Sorry, there was an issue processing your payment. Please try again.</p>
    </div>
  );
}

Setting up Stripe Webhook

Stripe webhooks are essential for listening to events and handling asynchronous processes, such as post-payment events, subscription updates, and more.

To set up a webhook, Create a new API route in your Next.js application to handle webhook events. Create a new file pages/api/webhooks.js and add the following code:

import Stripe from 'stripe';
import { buffer } from 'micro';

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

const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;

export const config = {
  api: {
    bodyParser: false,
  },
};

async function handleWebhookEvent(req, res) {
  const sig = req.headers['stripe-signature'];
  const buf = await buffer(req);

  let event;

  try {
    event = stripe.webhooks.constructEvent(buf.toString(), sig, webhookSecret);
  } catch (err) {
    console.error(`Webhook signature verification failed: ${err.message}`);
    return res.status(400).send(`Webhook signature verification failed: ${err.message}`);
  }

  switch (event.type) {
    case 'checkout.session.completed':
      const session = event.data.object;
      console.log(`Payment successful for session ID: ${session.id}`);
      // Handle post-payment actions here
      break;

    // Add other event types to handle as needed

    default:
      console.warn(`Unhandled event type: ${event.type}`);
  }

  res.status(200).end();
}

export default handleWebhookEvent;

This code sets up a webhook handler that listens for the checkout.session.completed event, which is triggered when a payment is successful. You can add more cases to handle additional event types as needed.

Add the webhook secret to .env.local:

Go to your Stripe dashboard and create a new webhook endpoint. Set the endpoint URL to https://your-domain.com/api/webhooks and select the events you want to listen for (e.g., checkout.session.completed). After creating the webhook, copy the webhook signing secret.

Add the webhook signing secret to your .env.local file:

STRIPE_WEBHOOK_SECRET=<your_webhook_secret>

Replace <your_webhook_secret> with the actual webhook secret from your Stripe dashboard.

To test the webhook locally, you can use tools like ngrok to expose your local server to the internet. Once you have ngrok installed, run the following command:

ngrok http 3000

This command will provide you with a public URL that forwards to your local server on port 3000. Update your webhook endpoint in the Stripe dashboard to point to this URL, followed by /api/webhooks.

Now, when an event is triggered, Stripe will send a request to the webhook handler in your Next.js application. You can handle the events as required in your business logic, such as sending confirmation emails, updating your database, or generating invoices.

With the webhook component set up, your Next.js application is now equipped to handle Stripe events and further enhance your  project's functionality.

Now, your Next.js application is ready to accept payments using Stripe Checkout! Test your application by running npm run dev and navigating to the page with the CheckoutButton component.

Conclusion

In this comprehensive tutorial, we've explored the essential steps to integrate Stripe Checkout with a Next.js application. By following this guide, you've learned how to create a secure and seamless payment experience, style your checkout components, and leverage the power of Stripe webhooks for handling events.

By implementing these features, your project is now poised for success, offering your customers a smooth and reliable purchasing experience. As a developer, staying informed about best practices and continually learning new technologies is key to staying ahead in this ever-evolving industry. We hope this tutorial has provided you with valuable insights and techniques that you can apply to future projects or enhance existing ones.

Remember, you can always adapt and extend the code provided in this tutorial to suit your specific needs, adding more features or integrating with other tools and services to build a powerful and scalable platform. Good luck, and happy coding!

Related posts

Tell us about your goals.

Every goal is a milestone waiting to be achieved. Share your vision with us, and let's turn aspirations into accomplishments together. We're all ears, ready to make your goals our mission.

Tell Us Where You Want To Be…

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.