Skip to main content
Copy this prompt to your AI code editor (Cursor, Copilot, Claude Code, etc.) to set up the integration automatically:

What You’ll Build

A complete checkout integration in Next.js including:
  • Server-side checkout session creation
  • Client-side redirect to hosted checkout
  • Webhook handling for payment confirmation
  • Protected routes based on payment status

Prerequisites

  • Next.js 13+ with App Router
  • Waffo Pancake account with API keys
  • A product created in Dashboard

Project Setup

1. Install Dependencies

2. Environment Variables

The SDK accepts private keys in multiple formats: PEM, base64, or raw — it auto-normalizes at construction time. Literal \n in .env files works too.

Create Checkout API Route

Create an API route to generate checkout sessions using the SDK:
The SDK automatically handles request signing — no manual header setup needed. Idempotency is opt-in: pass { idempotencyKey } as the last argument of a write (or of a server action) when a retry must not create a second record; nothing is sent, and nothing deduplicated, if you omit it.

Discounts

Discounts apply to one-time products, new subscriptions and plan changes. There are three settings on a checkout session; couponId cannot be combined with either of the others (sending both returns 400):
  • couponId applies a coupon the customer cannot change or remove
  • promotionCode pre-fills a code the customer can see — locked, unless you also pass allowPromotionCodes: true
  • allowPromotionCodes: true shows a code entry field on the checkout page (without it, the field is shown only when the store has a code that can be used on the product; false hides it)
Never take couponId or promotionCode from the request body. The route above signs with your API Key, so whatever the browser sends would be applied with your authority — a customer could apply any of your coupons to their own purchase. Decide the discount on the server:
If you use the @waffo/pancake-nextjs components, link checkout takes a discountCode (sent to the product page as discount_code, applied and locked), and the server action from createCheckoutAction() forwards allowPromotionCodes but strips couponId and promotionCode for the same reason. To apply a coupon or pre-fill a code, call @waffo/pancake-ts from your own server code as above.
See Discounts & Promotions for the rules and the reasons a code can be rejected.

Pricing Page Component

Create a pricing page with checkout buttons:

Webhook Handler

Handle payment confirmations using the SDK’s built-in verifyWebhook() — it has embedded public keys for both test and production environments, so you don’t need to manage webhook secrets:
The SDK’s verifyWebhook() uses embedded public keys — no WAFFO_WEBHOOK_SECRET environment variable needed. It also includes replay protection by default.

Success Page

Show confirmation after successful payment:

Protected Routes Middleware

Protect routes based on subscription status:

Server Component: Check Subscription


Let signed-in users manage their orders and subscriptions without an email code. A Route Handler on your server creates the portal link and redirects:
See Let Signed-In Customers Manage Orders for identity rules, session lifetime, and a version without the helper.

Complete File Structure


Testing Checklist

Before going live:
  • Test checkout flow with test card 4576 7500 0000 0110
  • Verify webhooks are received (check Dashboard logs)
  • Test declined payment with 4576 7500 0000 0220
  • Confirm success page displays correctly
  • Switch to live API keys
  • Update webhook URL to production endpoint

Next Steps

Handle Webhooks

Deep dive into webhook handling

Subscription Management

Advanced subscription features