Stripe Experts
Shopify IntegrationPlatformsIndustriesHire UsBlog
Book a Free Consultation
Stripe Experts

Trusted Stripe integration services for SaaS, marketplaces, and e-commerce.

Company

  • About
  • Blog
  • Contact

Services

  • All Services
  • Stripe Checkout
  • Stripe Connect
  • Stripe Billing

Hire Us

  • All Hiring Options
  • Hire a Stripe Expert
  • Hire a Developer
  • Hire a Stripe Consultant
  • Migrate to Stripe

Industries

  • SaaS
  • Marketplace
  • Healthcare
  • Fintech

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Stripe Experts. All rights reserved.

Not affiliated with Stripe, Inc. Independent Stripe integration partner.

Powered by mzkzeeshan

bussiness@mzkzeeshan.com

  1. Home
  2. Blog
  3. Stripe Tutorials
  4. How to Add Stripe to a Next.js 15 App Router Project
Stripe Tutorials

How to Add Stripe to a Next.js 15 App Router Project

Server Actions, Route Handlers, and the runtime gotcha that breaks most first attempts.

Z

Zeeshan

Founder · Published Jan 19, 2026

App Router changes the shape of a Stripe integration more than most teams expect. The old "API routes" mental model still mostly works, but two things trip up almost every first attempt: Server Actions for creating sessions, and the runtime configuration on your webhook handler.

Creating a Checkout Session

A Server Action is the cleanest way to create a Checkout Session from a form submission: no separate API route needed for the simple case.

"use server";

export async function createCheckoutSession() {
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    line_items: [{ price: "price_123", quantity: 1 }],
    success_url: `${process.env.SITE_URL}/success`,
    cancel_url: `${process.env.SITE_URL}/cancel`,
  });
  redirect(session.url!);
}

The Webhook Runtime Gotcha

Webhook signature verification needs the raw request body and Node.js APIs. It will not work on the Edge runtime. Explicitly force the Node runtime on your webhook route.

export const runtime = "nodejs";

export async function POST(req: Request) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature")!;
  const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  // handle event
}

Miss this and signature verification fails intermittently in production while working fine locally: a classic case of an environment difference masking the real bug.

#nextjs#checkout

Stripe insights, monthly

One email a month, no spam, unsubscribe anytime.

No spam, unsubscribe anytime.

On This Page

  • Creating a Checkout Session
  • The Webhook Runtime Gotcha

Related Services

Stripe Checkout

Fully hosted, brand-matched Stripe Checkout, live in days.

Learn more

Webhooks

Production-grade Stripe webhook handling, verified and monitored.

Learn more

API Integration

Custom Stripe API integration for your exact business logic.

Learn more

Related Reading

Stripe Tutorials

Subscriptions in Django with Stripe Billing

Let Stripe own the billing state and Django own the entitlement. Mixing the two is where it goes wrong.

Aug 10, 2026Read
Stripe Tutorials

Stripe in PHP: Checkout Sessions and Webhook Verification Done Right

The raw-body problem bites PHP integrations harder than most. Here's the correct shape.

Jul 6, 2026Read
Stripe Tutorials

Integrating Stripe Payment Element in React Without the Common Pitfalls

The Elements provider, the client secret lifecycle, and the re-render bug that breaks most first attempts.

Jun 22, 2026Read