Stripe Checkout not working - 404 error when using Next.js App Router

46 Views Asked by At

I'm trying to add a simple Stripe checkout to a Next.js App router app. The code works if I'm using the pages router in next.js but not in App router for some reason I get a 404 - This page could not be found error when I click the checkout button. Anyone know why that is happening?

Got the code here:

app/page.js:

'use client'

import React from 'react';
import { loadStripe } from '@stripe/stripe-js';

// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe(
  process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
);
export default function PreviewPage() {
  React.useEffect(() => {
    // Check to see if this is a redirect back from Checkout
    const query = new URLSearchParams(window.location.search);
    if (query.get('success')) {
      console.log('Order placed! You will receive an email confirmation.');
    }

    if (query.get('canceled')) {
      console.log('Order canceled -- continue to shop around and checkout when you’re ready.');
    }
  }, []);

  return (
    <form action="/api/checkout_sessions" method="POST">
      <section>
        <button type="submit" role="link">
          Checkout
        </button>
      </section>
      <style jsx>
        {`
          section {
            background: #ffffff;
            display: flex;
            flex-direction: column;
            width: 400px;
            height: 112px;
            border-radius: 6px;
            justify-content: space-between;
          }
          button {
            height: 36px;
            background: #556cd6;
            border-radius: 4px;
            color: white;
            border: 0;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
            box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
          }
          button:hover {
            opacity: 0.8;
          }
        `}
      </style>
    </form>
  );
}

app/api/checkout_sessions/route.js:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      // Create Checkout Sessions from body params.
      const session = await stripe.checkout.sessions.create({
        line_items: [
          {
            price: 'price_id',
            quantity: 1,
          },
        ],
        mode: 'subscription',
        success_url: `${req.headers.origin}/?success=true`,
        cancel_url: `${req.headers.origin}/?canceled=true`,
      });
      res.redirect(303, session.url);
    } catch (err) {
      res.status(err.statusCode || 500).json(err.message);
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}
2

There are 2 best solutions below

3
Mayank Sethi On

Sounds like you're facing a common hiccup with Next.js and its routing, especially when integrating something like Stripe. Given the details, it seems like the issue might be related to how you've structured your API route in your Next.js app.

In Next.js, API routes are meant to be placed under the pages/api directory. This setup is crucial for Next.js to correctly recognize and handle API requests. From your code snippet, it looks like you've placed your checkout_sessions route within an app/api/checkout_sessions/route.js path.

Here's a quick suggestion to potentially fix the 404 error:

  1. Move Your API Route: Ensure your API route (checkout_sessions) is directly under the pages/api directory. The correct path would be pages/api/checkout_sessions.js. This adjustment should help Next.js recognize your API route properly.

  2. Adjust the Form Action: After moving your API route file, make sure the form's action in your PreviewPage component points to the correct endpoint. Since your API route will now be at pages/api/checkout_sessions.js, your form action should be set to /api/checkout_sessions which it already seems to be, so you're good here.

By moving your API route to the correct directory, Next.js should be able to properly handle requests to /api/checkout_sessions without returning a 404 error. Give this a try and it should help with the checkout button issue. If there are any more bumps along the way or anything else you wanna chat about, just let me know!

0
grekier On

I think I've seen this error around 100 times on SO now. API endpoints in app router must look like:

export async function POST(req: Request) {
// ...
}

or

export async function GET(req: Request) {
// ...
}

With the verb associated with the what you want to allow. See https://nextjs.org/docs/app/building-your-application/routing/route-handlers for more details.