Fix Stripe Webhook on Vercel Edge Runtime

The Stripe SDK uses Buffer internally, which doesn't exist on Vercel Edge Runtime or Cloudflare Workers. You need to verify the signature manually using the Web Crypto API.

Error you'll see: ReferenceError: Buffer is not defined or stripe.webhooks.constructEvent is not a function on Edge Runtime.

The complete Edge Runtime handler

// app/api/webhooks/stripe/route.ts
export const runtime = 'edge'; // or 'nodejs' to avoid this entirely

import { NextResponse } from 'next/server';

const secret = process.env.STRIPE_WEBHOOK_SECRET!;

export async function POST(request: Request) {
  const body = await request.text();
  const sig  = request.headers.get('stripe-signature');

  if (!sig) {
    return NextResponse.json({ error: 'Missing stripe-signature' }, { status: 400 });
  }

  let event: any;
  try {
    // Parse the Stripe-Signature header
    const parts     = sig.split(',');
    const timestamp = parts.find(p => p.startsWith('t='))?.slice(2);
    const v1        = parts.find(p => p.startsWith('v1='))?.slice(3);

    if (!timestamp || !v1) throw new Error('Invalid signature format');

    // Import HMAC key using Web Crypto API (works on Edge)
    const key = await crypto.subtle.importKey(
      'raw',
      new TextEncoder().encode(secret),
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['verify']
    );

    // Stripe signs: timestamp + '.' + payload
    const signed   = new TextEncoder().encode(\`\${timestamp}.\${body}\`);
    const sigBytes = Uint8Array.from(
      v1.match(/.{2}/g)!.map(h => parseInt(h, 16))
    );

    const valid = await crypto.subtle.verify('HMAC', key, sigBytes, signed);
    if (!valid) throw new Error('Signature mismatch');

    event = JSON.parse(body);
  } catch (err: any) {
    return NextResponse.json({ error: \`Webhook Error: \${err.message}\` }, { status: 400 });
  }

  switch (event.type) {
    case 'checkout.session.completed':
      // fulfill order
      break;
  }

  return NextResponse.json({ received: true });
}

Simpler alternative — use Node.js runtime

If you don't specifically need Edge Runtime, switching to Node.js runtime lets you use the Stripe SDK directly:

// app/api/webhooks/stripe/route.ts
export const runtime = 'nodejs'; // ← add this line

import Stripe from 'stripe'; // now works normally
import { NextResponse } from 'next/server';
// ... rest of the standard handler

Generate the Edge Runtime handler with the Edge toggle enabled.

Open WebhookFix →
For informational purposes only. Always test in staging before production. MetricLogic accepts no responsibility for issues arising from use of these tools. © 2026 MetricLogic.
HttpFixer by MetricLogic · Blog · All Tools · Generators MIT · GitHub →