Next.js Discord

Discord Forum

NextJS and stripe webhook

Unanswered
Pacific herring posted this in #help-forum
Open in Discord
Pacific herringOP
Okay im using Supabase as backend for my nextjs application, I have this route :
import Stripe from 'stripe';

import { stripe } from '@/lib/stripe/stripe';
import {
  upsertProductRecord,
  upsertPriceRecord,
  manageSubscriptionStatusChange,
  deletePriceRecord,
  deleteProductRecord,
} from '@/lib/supabase/supabase-admin';

export async function POST(request: Request) {
  const body = await request.text();
  const sig = request.headers.get('stripe-signature') as string;
  const webhookSecret = process.env.NEXT_PUBLIC_STRIPE_WEBHOOK_SECRET;
  let event: Stripe.Event;
  console.log(`🔔 Webhook received: sig:${sig}, body:${body}, webhookSecret:${webhookSecret}`);
  
  try {
    if (!sig || !webhookSecret)
      return new Response('Webhook secret not found.', { status: 400 });
    event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
    console.log(`🔔  Webhook received: ${event.type}`);
  } catch (err: any) {
    console.log(`❌ Error message: ${err.message}`);
    return new Response(`Webhook Error: ${err.message}`, { status: 400 });
  }

  if (relevantEvents.has(event.type)) {
    try {
      switch (event.type) {
        case 'product.created':
        case 'product.updated':
          await upsertProductRecord(event.data.object as Stripe.Product);
          break;
        {...}
        default:
          throw new Error('Unhandled relevant event!');
      }
    } catch (error) {
      console.log(error);
      return new Response(
        'Webhook handler failed. View your Next.js function logs.',
        {
          status: 400
        }
      );
    }
  } else {
    return new Response(`Unsupported event type: ${event.type}`, {
      status: 400
    });
  }
  return new Response(JSON.stringify({ received: true }));
}

58 Replies

Pacific herringOP
Its very new because its was working before idk why but there is the log from stripe :
Webhook Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? 
Learn more about webhook signing and explore webhook integration examples for various frameworks at https://github.com/stripe/stripe-node#webhook-signing

I try on local (with dev nextjs) and stripe.webhooks.constructEvent seems to work properly
@gin the production build is on vercel?
Pacific herringOP
No im using Coolify with the Dockerfile give as example by nextjs
@gin cause in your current setup u parse it to text
Pacific herringOP
but all Supabase and Stripe examlpe do this
And seems weird if its working on dev mode but not after build in Coolify
@Pacific herring but all `Supabase` and `Stripe` examlpe do this
i checked this
they are using the raw body
idk why the specifying a type but the body is raw
Pacific herringOP
Using request.body i have this :
The argument of type 'ReadableStream<Uint8Array> | null' is not assignable to the parameter of type 'string | Buffer'.
Cannot assign type 'null' to type 'string | Buffer'.ts(2345)
Pacific herringOP
But this seems weird because in production mode, I have already a console.log and I can see const body = await request.text(); return something good
even if stripe.webhooks.constructEvent fail
yeah thats obviously works
but i think they expect the body as unparsed and not consumed
just raw buffer
i could be wrong
but try that
try this
const rawBody = await buffer(req);
const body = JSON.parse(rawBody.toString());
@Pacific herring buffer function is from this lib -> micro
npm i micro
after that u can try passing rawBody directly and if that throws something try it with the parsed json body from the raw body
@gin try this typescript const rawBody = await buffer(req); const body = JSON.parse(rawBody.toString());
Pacific herringOP
I have this error on buffer :
The argument of type 'Request' is not assignable to the parameter of type 'IncomingMessage'. The type 'Request' is missing the following properties from type 'IncomingMessage': aborted, httpVersion, httpVersionMajor, httpVersionMinor, and 50 others.

Maybe I can try updating stripe lib ?
@gin where did that happen?
Pacific herringOP
When over buffer in vscode because my request variable was underline in red
@gin u used buffer from micro?
Pacific herringOP
yes
@Pacific herring yes
can u try disabling typescript for that?
//@ts-ignore
i found a thread talking about this exact issue
@gin can u try disabling typescript for that?
Pacific herringOP
nah cant dodge this :
POST /api/stripe 500 in 345ms
 ⨯ HttpError: Invalid body
    at createError (webpack-internal:///(rsc)/./node_modules/micro/dist/src/lib/index.js:34:17)
    at eval (webpack-internal:///(rsc)/./node_modules/micro/dist/src/lib/index.js:139:43)
    at async POST (webpack-internal:///(rsc)/./src/app/api/stripe/route.ts:25:18)
    at async /Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:53238
    at async e_.execute (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:44501)
    at async e_.handle (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:54492)
    at async doRender (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/server/base-server.js:1372:42)
    at async cacheEntry.responseCache.get.routeKind (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/server/base-server.js:1594:28)
@gin https://www.reddit.com/r/nextjs/comments/tt4qbf/comment/i2vgki8/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
Pacific herringOP
but this was for nextjs using page route not app router if I well understood
@gin this happened when passing in the whole req?
Pacific herringOP
yes
what happens when u just pass the body?
req.body
@gin what happens when u just pass the body?
Pacific herringOP
⨯ TypeError: Cannot read properties of undefined (reading 'content-type')
    at eval (webpack-internal:///(rsc)/./node_modules/micro/dist/src/lib/index.js:119:29)
    at async POST (webpack-internal:///(rsc)/./src/app/api/stripe/route.ts:25:18)
    at async /Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:53238
    at async e_.execute (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:44501)
    at async e_.handle (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:54492)
    at async doRender (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/server/base-server.js:1372:42)
    at async cacheEntry.responseCache.get.routeKind (/Users/loup/Projects/DEV/Recomend/recomend-web-app/node_modules/next/dist/server/base-server.js:1594:28)
 
Im gonna try to build image locally and run it in my computer
just to see if its depend of hoster
i could help u out via vscode liveshare
@gin alr
Pacific herringOP
well its working on my computer...
Maybe the problem come from coolify
hello i also want to know on stripe can we schedule custom email before the subscription end on stripe webhook?
@Krishna hello i also want to know on stripe can we schedule custom email before the subscription end on stripe webhook?
Pacific herringOP
sry idk about it, maybe open a help post for ur request
@gin alr
Pacific herringOP
maybe the problem come from :
sig:t=1726852343,v1=54917084b5ffae814c0fff332aa43e90e4a922c4637d5e3a5bc098a23bbe4f4c,v0=a091a14f897e3b23cab124129011c10738480e174c6500c88292627c0a39b2bd

in fact in local i have t, v1 and v0 but when calling api route from production i have only t and v1
Pacific herringOP
arhh im tired of nextjs ahah so hard to debug
Pacific herringOP
Pacific herringOP
shame on me, I fix the problem... im so sry for this useless issue