Next.js Discord

Discord Forum

Stripe not working properly with nextjs 14

Answered
Armenian Gampr dog posted this in #help-forum
Open in Discord
Armenian Gampr dogOP
Hi,
im trying to test stripe locally.
I have create this route handler from stripe doc and others people code stackoverflow:

// app/api/stripe/webhook.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2023-10-16',
});

// Middleware to disable body parsing
export const config = {
  runtime: 'experimental-edge',
  api: {
    bodyParser: false,
  },
};

export async function POST(req: NextRequest) {
  console.log('POST')
  const sig = req.headers.get('stripe-signature');
  const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
  let event: Stripe.Event;

  try {
    const body = await req.text();
    if (!sig || !webhookSecret) {
      throw new Error('Missing Stripe Signature');
    }
    event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
  } catch (err: any) {
    console.error(`❌ Error message: ${err.message}`);
    return new NextResponse(`Webhook Error: ${err.message}`, {
      status: 400,
    });
  }

  try {
    switch (event.type) {
      case 'product.created':
        // Handle product created event
        break;
      case 'product.updated':
        // Handle product updated event
        break;
      default:
        throw new Error('Unhandled relevant event!');
    }
  } catch (error: any) {
    console.error(`Error in processing webhook: ${error.message}`);
    return new NextResponse('Webhook handler failed. View logs.', {
      status: 400,
    });
  }

  return new NextResponse(JSON.stringify({ received: true }), {
    status: 200,
    headers: {
      'Content-Type': 'application/json',
    },
  });
}


Im listening to this :
stripe listen --forward-to localhost:3000/api/stripe/webhook

and trigger with this:
stripe trigger payment_intent.succe

my question is why i don't see the console.log in the terminal?

this is the what i get from the listen:
2023-12-12 21:37:36  <--  [307] POST http://localhost:3000/api/stripe/webhook [evt_3OMchtElNHG3Wsnf05cJC5Tn]
2023-12-12 21:37:36   --> payment_intent.created [evt_3OMchtElNHG3Wsnf0d81p2rp]2023-12-12 21:37:36  <--  [307] POST http://localhost:3000/api/stripe/webhook [evt_3OMchtElNHG3Wsnf0d81p2rp]
2023-12-12 21:37:36   --> checkout.session.completed [evt_1OMchwElNHG3WsnfbQT5PxFE]
2023-12-12 21:37:36  <--  [307] POST http://localhost:3000/api/stripe/webhook [evt_1OMchwElNHG3WsnfbQT5PxFE]


Base from the support of stripe told me this:
So the issue is that Stripe doesn't allow redirects for endpoints. I'm not sure what in your integration is causing a temporary redirect to happen, but whatever it is, you'll need to disallow redirects completely so that the webhook can directly access the endpoint


I dont have any redirect code from the route handler nor in any or global middleware.

So how can i see the data coming from stripe?
Answered by Ray
move it to app/api
View full answer

37 Replies

@Armenian Gampr dog Hi, im trying to test stripe locally. I have create this route handler from stripe doc and others people code stackoverflow: // app/api/stripe/webhook.ts import { NextRequest, NextResponse } from 'next/server'; import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2023-10-16', }); // Middleware to disable body parsing export const config = { runtime: 'experimental-edge', api: { bodyParser: false, }, }; export async function POST(req: NextRequest) { console.log('POST') const sig = req.headers.get('stripe-signature'); const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!; let event: Stripe.Event; try { const body = await req.text(); if (!sig || !webhookSecret) { throw new Error('Missing Stripe Signature'); } event = stripe.webhooks.constructEvent(body, sig, webhookSecret); } catch (err: any) { console.error(`❌ Error message: ${err.message}`); return new NextResponse(`Webhook Error: ${err.message}`, { status: 400, }); } try { switch (event.type) { case 'product.created': // Handle product created event break; case 'product.updated': // Handle product updated event break; default: throw new Error('Unhandled relevant event!'); } } catch (error: any) { console.error(`Error in processing webhook: ${error.message}`); return new NextResponse('Webhook handler failed. View logs.', { status: 400, }); } return new NextResponse(JSON.stringify({ received: true }), { status: 200, headers: { 'Content-Type': 'application/json', }, }); } Im listening to this : stripe listen --forward-to localhost:3000/api/stripe/webhook and trigger with this: stripe trigger payment_intent.succe my question is why i don't see the console.log in the terminal? this is the what i get from the listen: 2023-12-12 21:37:36 <-- [307] POST http://localhost:3000/api/stripe/webhook [evt_3OMchtElNHG3Wsnf05cJC5Tn] 2023-12-12 21:37:36 --> payment_intent.created [evt_3OMchtElNHG3Wsnf0d81p2rp]2023-12-12 21:37:36 <-- [307] POST http://localhost:3000/api/stripe/webhook [evt_3OMchtElNHG3Wsnf0d81p2rp] 2023-12-12 21:37:36 --> checkout.session.completed [evt_1OMchwElNHG3WsnfbQT5PxFE] 2023-12-12 21:37:36 <-- [307] POST http://localhost:3000/api/stripe/webhook [evt_1OMchwElNHG3WsnfbQT5PxFE] Base from the support of stripe told me this: So the issue is that Stripe doesn't allow redirects for endpoints. I'm not sure what in your integration is causing a temporary redirect to happen, but whatever it is, you'll need to disallow redirects completely so that the webhook can directly access the endpoint I dont have any redirect code from the route handler nor in any or global middleware. So how can i see the data coming from stripe?
just test your code without problem
is there a middleware.ts in your project?
@Ray just test your code without problem
Armenian Gampr dogOP
Didn't you get the 307 from the listener?
2023-12-13 05:34:18   --> charge.succeeded [evt_3OMdanJwScrLsTSM1PazHM7v]
2023-12-13 05:34:19   --> payment_intent.succeeded [evt_3OMdanJwScrLsTSM1RpjtfRs]
2023-12-13 05:34:19   --> payment_intent.created [evt_3OMdanJwScrLsTSM15mrRVVy]
2023-12-13 05:34:19  <--  [200] POST http://localhost:3000/api/stripe [evt_3OMdanJwScrLsTSM1RpjtfRs]
2023-12-13 05:34:19  <--  [400] POST http://localhost:3000/api/stripe [evt_3OMdanJwScrLsTSM15mrRVVy]
2023-12-13 05:34:19  <--  [400] POST http://localhost:3000/api/stripe [evt_3OMdanJwScrLsTSM1PazHM7v]

no i get 200
@Ray is there a middleware.ts in your project?
Armenian Gampr dogOP
Yes
import { pathnames, locales } from './navigation';
import { createServerClient, type CookieOptions } from '@supabase/ssr';
import { type NextRequest, NextResponse } from 'next/server';

// export const createClient = (request: NextRequest) => {
//   // Create an unmodified response
//   let response = NextResponse.next({
//     request: {
//       headers: request.headers,
//     },
//   });

//   const supabase = createServerClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, {
//     cookies: {
//       get(name: string) {
//         return request.cookies.get(name)?.value;
//       },
//       set(name: string, value: string, options: CookieOptions) {
//         // If the cookie is updated, update the cookies for the request and response
//         request.cookies.set({
//           name,
//           value,
//           ...options,
//         });
//         response = NextResponse.next({
//           request: {
//             headers: request.headers,
//           },
//         });
//         response.cookies.set({
//           name,
//           value,
//           ...options,
//         });
//       },
//       remove(name: string, options: CookieOptions) {
//         // If the cookie is removed, update the cookies for the request and response
//         request.cookies.set({
//           name,
//           value: '',
//           ...options,
//         });
//         response = NextResponse.next({
//           request: {
//             headers: request.headers,
//           },
//         });
//         response.cookies.set({
//           name,
//           value: '',
//           ...options,
//         });
//       },
//     },
//   });

//   return { supabase, response };
// };

export default createMiddleware({
  defaultLocale: 'en',
  localePrefix: 'always',
  locales,
  pathnames,
});

export const config = {
  matcher: ['/((?!_next|.*\\..*).*)', '/', '/(en|fr|nl)/:path*'],
};
does it work if you rename it to _middleware.ts
Armenian Gampr dogOP
Give me sec Imma try that.
export const config = {
  matcher: ["/((?!api|_next|.*\\..*).*)", "/", "/(en|fr|nl)/:path*"],
};

change the matcher to this, I added !api there
@Ray ts export const config = { matcher: ["/((?!api|_next|.*\\..*).*)", "/", "/(en|fr|nl)/:path*"], }; change the matcher to this, I added !api there
Armenian Gampr dogOP
i get 404:
2023-12-12 22:46:40   --> charge.succeeded [evt_3OMdmlElNHG3Wsnf0PmbplOw]
2023-12-12 22:46:40  <--  [404] POST http://localhost:3000/api/stripe/webhook [evt_3OMdmlElNHG3Wsnf0PmbplOw]
2023-12-12 22:46:40   --> payment_intent.succeeded [evt_3OMdmlElNHG3Wsnf0qrOtAtw]
2023-12-12 22:46:40  <--  [404] POST http://localhost:3000/api/stripe/webhook [evt_3OMdmlElNHG3Wsnf0qrOtAtw]
2023-12-12 22:46:40   --> payment_intent.created [evt_3OMdmlElNHG3Wsnf0xUxFRFe]
2023-12-12 22:46:40  <--  [404] POST http://localhost:3000/api/stripe/webhook [evt_3OMdmlElNHG3Wsnf0xUxFRFe]
oh the file should be app/api/stripe/webhook/route.ts
instead of app/api/stripe/webhook.ts
Armenian Gampr dogOP
it is app/api/stripe/webhook/route.ts
it should works after you change it
oh
add below to app/api/stripe/webhook/route.ts
export function GET() {
  return new Response("HI")
}
Armenian Gampr dogOP
did you rename the middleware to _middleware.ts or changed the matcher
@Ray did you rename the middleware to _middleware.ts or changed the matcher
Armenian Gampr dogOP
yes and also change the matcher
@Ray then go visit http://localhost:3000/api/stripe/webhook
Armenian Gampr dogOP
i get 404 page not found
with NEXT_NOT_FOUND
@Ray then go visit http://localhost:3000/api/stripe/webhook
can you show full image of your folder structure?
Armenian Gampr dogOP
im listening to this:
stripe listen --forward-to localhost:3000/api/stripe/webhook

should i add route.ts?
@Ray can you show full image of your folder structure?
Armenian Gampr dogOP
ah
your api folder is under app/[locale]
move it to app/api
Answer
your don't need to support multiple langage in api right?
@Ray your don't need to support multiple langage in api right?
Armenian Gampr dogOP
nope but will need to reroute it. And it worked and i moved the api to app/api/.

Your a GOAT like your profile picture bro
just got this error:
POST
POST
POST
❌ Error message: Missing Stripe Signature
❌ Error message: Missing Stripe Signature
❌ Error message: Missing Stripe Signature

xd
but now i can work on solving this thanks a lot
cool, please mark solution if your issue has been fixed
Armenian Gampr dogOP
mark solution? sorry first time using this new discord feature
right click the answer > application > mark solution
don't forget to rename back your middleware
Armenian Gampr dogOP
Thanks GOAT
np