π° Cash Rules Everything Around Me - Integrating Stripe & Next.js
Integrating Stripe into your JavaScript Web App to take payments for your product
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.
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.
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.
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.
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.
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.
1// Success page
2
3export default function Success() {
4 return <h1>Payment Successful! Thank you for your purchase.</h1>;
5}
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.
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.
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.