### Build and Start Production Server
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Build the Next.js application for production and start the production server.
```bash
npm run build
npm start
```
--------------------------------
### Install Project Dependencies
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Run this command after cloning the repository to install all necessary Node.js dependencies.
```bash
npm install
```
--------------------------------
### Run Development Server
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Start the Next.js development server to view your application locally. Access it at http://localhost:3000.
```bash
npm run dev
```
--------------------------------
### Configure Environment Variables
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Copy the example environment file and update it with your Dodo Payments API and webhook keys, return URL, and environment mode.
```bash
cp .env.example .env
```
```env
DODO_PAYMENTS_API_KEY=your_api_key_here
DODO_PAYMENTS_WEBHOOK_KEY=your_webhook_signing_key_here
DODO_PAYMENTS_RETURN_URL=http://localhost:3000
DODO_PAYMENTS_ENVIRONMENT=test_mode
```
--------------------------------
### GET /api/customer-portal — Customer Portal Redirect
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Redirects the user to their Dodo Payments self-service portal using the CustomerPortal handler. Requires a customer_id query parameter.
```APIDOC
## GET /api/customer-portal — Customer Portal Redirect
### Description
Redirects the user to their Dodo Payments self-service portal where they can manage subscriptions, update billing, and view invoices. This handler accepts a `customer_id` query parameter and uses the `CustomerPortal` helper from `@dodopayments/nextjs`.
### Method
GET
### Endpoint
`/api/customer-portal`
### Query Parameters
- **customer_id** (string) - Required - The ID of the customer.
### Request Example
```bash
curl -L "http://localhost:3000/api/customer-portal?customer_id=cus_001"
```
### Response
#### Success Response (302)
A 302 redirect to the Dodo Payments customer portal.
#### Response Example
```
302 redirect → https://portal.dodopayments.com/customers/cus_001/...
```
### Usage Example (UI Link)
```tsx
// src/app/components/Header.tsx — linking to the portal from the UI
const CUSTOMER_ID = "cus_001"; // Replace with the authenticated user's customer ID
Customer Portal
```
```
--------------------------------
### GET /api/checkout — Static Checkout Link
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Generates a static checkout URL using the Checkout helper with type 'static'. This is suitable for embedding in links or buttons without requiring a cart payload.
```APIDOC
## GET /api/checkout — Static Checkout Link
### Description
Generates a static checkout URL suitable for embedding in links or buttons. It uses the `Checkout` helper from `@dodopayments/nextjs` with `type: "static"`.
### Method
GET
### Endpoint
`/api/checkout`
### Query Parameters
- **product_id** (string) - Required - The ID of the product to generate a checkout link for.
### Request Example
```bash
curl "http://localhost:3000/api/checkout?product_id=pdt_001"
```
### Response
#### Success Response (200)
- **checkout_url** (string) - The generated static checkout URL.
#### Response Example
```json
{
"checkout_url": "https://checkout.dodopayments.com/static/pdt_001?...")
}
```
```
--------------------------------
### Set up Local Webhook Testing with ngrok
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Use ngrok to expose your local development server to the internet, allowing Dodo Payments to send webhook events to your local endpoint. Set the ngrok URL as your webhook endpoint in the Dodo Payments Dashboard.
```bash
# Testing locally with ngrok
ngrok http 3000
# Then set the ngrok URL as your webhook endpoint in the Dodo Payments Dashboard:
# https://.ngrok.io/api/webhook
```
--------------------------------
### Create Session-Based Checkout with Next.js
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Use the `Checkout` helper with `type: "session"` to create a dynamic checkout session. The request body should contain a product cart and optional customer information. The response provides a `checkout_url` for client redirection.
```typescript
export const POST = Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
type: "session",
});
```
```bash
curl -X POST "http://localhost:3000/api/checkout" \
-H "Content-Type: application/json" \
-d '{
"product_cart": [
{ "product_id": "pdt_001", "quantity": 1 }
],
"customer": {
"name": "Jane Smith",
"email": "jane@example.com"
}
}'
# Response: { "checkout_url": "https://checkout.dodopayments.com/session/..." }
```
--------------------------------
### Environment Configuration for Dodo Payments
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Configure Dodo Payments API credentials and runtime settings using environment variables. Ensure these are set in a `.env` file at the project root.
```bash
# .env
DODO_PAYMENTS_API_KEY=your_api_key_here # From Dashboard → Developer → API Keys
DODO_PAYMENTS_WEBHOOK_KEY=your_webhook_key_here # From Dashboard → Developer → Webhooks
DODO_PAYMENTS_RETURN_URL=http://localhost:3000 # Redirect URL after checkout completes
DODO_PAYMENTS_ENVIRONMENT=test_mode # "test_mode" | "live_mode"
```
--------------------------------
### Define Products in TypeScript
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Update this file with your product IDs, names, descriptions, prices, and features obtained from the Dodo Payments dashboard.
```typescript
export const products: Product[] = [
{
product_id: "pdt_001", // Replace with your product ID
name: "Basic Plan",
description: "Get access to basic features and support",
price: 9999, // in cents
features: [
"Access to basic features",
"Email support",
"1 Team member",
"Basic analytics",
],
},
// ... add more products
];
```
--------------------------------
### Initiate Checkout from UI with React Component
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Implement a client-side React component to display product information and initiate a checkout session. This component handles loading states, errors, and redirects the user to the checkout URL provided by the API.
```tsx
// src/app/components/ProductCard.tsx (simplified usage flow)
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { Product } from "@/lib/products";
export default function ProductCard({ product }: { product: Product }) {
const [loading, setLoading] = useState(false);
const router = useRouter();
const initiateCheckout = async (productId: string) => {
try {
setLoading(true);
const response = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
product_cart: [{ product_id: productId, quantity: 1 }],
customer: {
name: "John Doe", // Replace with authenticated user data
email: "john@example.com", // Replace with authenticated user data
},
}),
});
if (!response.ok) throw new Error("Failed to initiate checkout");
const data = await response.json();
if (data.checkout_url) router.push(data.checkout_url);
} catch (error) {
console.error("Checkout error:", error);
alert("Failed to initiate checkout. Please try again.");
} finally {
setLoading(false);
}
};
return (
{product.name}
${(product.price / 100).toFixed(2)}/mo
);
}
// Rendering the pricing page with all products:
// src/app/page.tsx
import ProductCard from "./components/ProductCard";
import { products } from "@/lib/products";
export default function Home() {
return (
{products.map((product) => (
))}
);
}
```
--------------------------------
### Checkout Initiation
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
The `ProductCard` component initiates the checkout process by sending a POST request to `/api/checkout` with product and customer details. It handles loading states, errors, and redirects the user to the checkout URL.
```APIDOC
## `ProductCard` Component — Checkout Initiation from the UI
`ProductCard` is the client-side React component that renders a product's pricing information and triggers a session checkout by POSTing to `/api/checkout`. It handles loading state, error display, and redirects the user to the `checkout_url` returned by the API.
```tsx
// src/app/components/ProductCard.tsx (simplified usage flow)
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { Product } from "@/lib/products";
export default function ProductCard({ product }: { product: Product }) {
const [loading, setLoading] = useState(false);
const router = useRouter();
const initiateCheckout = async (productId: string) => {
try {
setLoading(true);
const response = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
product_cart: [{ product_id: productId, quantity: 1 }],
customer: {
name: "John Doe", // Replace with authenticated user data
email: "john@example.com", // Replace with authenticated user data
},
}),
});
if (!response.ok) throw new Error("Failed to initiate checkout");
const data = await response.json();
if (data.checkout_url) router.push(data.checkout_url);
} catch (error) {
console.error("Checkout error:", error);
alert("Failed to initiate checkout. Please try again.");
} finally {
setLoading(false);
}
};
return (
{product.name}
${(product.price / 100).toFixed(2)}/mo
);
}
// Rendering the pricing page with all products:
// src/app/page.tsx
import ProductCard from "./components/ProductCard";
import { products } from "@/lib/products";
export default function Home() {
return (
{products.map((product) => (
))}
);
}
```
```
--------------------------------
### Clone Repository with Git
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Use this command to clone the boilerplate repository to your local machine.
```bash
git clone https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate.git
cd dodo-nextjs-minimal-boilerplate
```
--------------------------------
### Define Product Catalog in TypeScript
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Define your products as a static TypeScript array, mapping each product to a Dodo Payments product ID and including display metadata. This array is consumed by components like `ProductCard`.
```typescript
// src/lib/products.ts
export type Product = {
product_id: string; // Must match a product ID in your Dodo Payments dashboard
name: string;
description: string;
price: number; // Price in cents (e.g. 9999 = $99.99)
features: string[];
};
export const products: Product[] = [
{
product_id: "pdt_001",
name: "Basic Plan",
description: "Get access to basic features and support",
price: 9999,
features: [
"Access to basic features",
"Email support",
"1 Team member",
"Basic analytics",
],
},
{
product_id: "pdt_002",
name: "Premium Plan",
description: "Get access to premium features and support",
price: 19999,
features: [
"Access to all features",
"Priority 24/7 support",
"Unlimited team members",
"Advanced analytics",
"Custom integrations",
],
},
];
```
--------------------------------
### Generate Static Checkout Link with Next.js
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Use the `Checkout` helper with `type: "static"` to generate a static checkout URL. This is suitable for embedding in links or buttons. Append `product_id` as a query parameter.
```typescript
// src/app/api/checkout/route.ts
import { Checkout } from "@dodopayments/nextjs";
export const GET = Checkout({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
returnUrl: process.env.DODO_PAYMENTS_RETURN_URL,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
type: "static",
});
```
```bash
# Usage: append product_id as a query parameter
curl "http://localhost:3000/api/checkout?product_id=pdt_001"
# Response: { "checkout_url": "https://checkout.dodopayments.com/..." }
```
--------------------------------
### Redirect to Customer Portal with Next.js
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Utilize the `CustomerPortal` handler to redirect users to their Dodo Payments self-service portal. This handler requires a `customer_id` query parameter. It's useful for linking to the portal from your application's UI.
```typescript
// src/app/api/customer-portal/route.ts
import { CustomerPortal } from "@dodopayments/nextjs";
export const GET = CustomerPortal({
bearerToken: process.env.DODO_PAYMENTS_API_KEY!,
environment: process.env.DODO_PAYMENTS_ENVIRONMENT as "test_mode" | "live_mode",
});
```
```bash
curl -L "http://localhost:3000/api/customer-portal?customer_id=cus_001"
# Response: 302 redirect → https://portal.dodopayments.com/customers/cus_001/...
```
```tsx
// src/app/components/Header.tsx — linking to the portal from the UI
const CUSTOMER_ID = "cus_001"; // Replace with the authenticated user's customer ID
Customer Portal
```
--------------------------------
### Product Catalog Definition
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Defines the product catalog as a static TypeScript array, mapping each product to its ID, display metadata, and price. This is used by the `ProductCard` component.
```APIDOC
## Product Catalog — `src/lib/products.ts`
Products are defined as a static TypeScript array exported from `src/lib/products.ts`. Each entry maps directly to a Dodo Payments product ID and carries display metadata (name, description, price in cents, feature list) consumed by the `ProductCard` component.
```typescript
// src/lib/products.ts
export type Product = {
product_id: string; // Must match a product ID in your Dodo Payments dashboard
name: string;
description: string;
price: number; // Price in cents (e.g. 9999 = $99.99)
features: string[];
};
export const products: Product[] = [
{
product_id: "pdt_001",
name: "Basic Plan",
description: "Get access to basic features and support",
price: 9999,
features: [
"Access to basic features",
"Email support",
"1 Team member",
"Basic analytics",
],
},
{
product_id: "pdt_002",
name: "Premium Plan",
description: "Get access to premium features and support",
price: 19999,
features: [
"Access to all features",
"Priority 24/7 support",
"Unlimited team members",
"Advanced analytics",
"Custom integrations",
],
},
];
```
```
--------------------------------
### Handle Webhook Events with Dodo Payments
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Implement a webhook handler to verify request signatures and dispatch typed event payloads to specific callbacks. Ensure your DODO_PAYMENTS_WEBHOOK_KEY is set in your environment variables.
```typescript
// src/app/api/webhook/route.ts
import { Webhooks } from "@dodopayments/nextjs";
export const POST = Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY!,
onSubscriptionActive: async (payload) => {
// payload contains subscriber and subscription metadata
console.log("Subscription activated:", payload);
// e.g., grant product access, write to database, send welcome email
await db.users.update({ customerId: payload.customer.id, plan: "active" });
},
onPaymentSucceeded: async (payload) => {
console.log("Payment succeeded:", payload);
// e.g., fulfil order, send receipt email
await sendReceiptEmail(payload.customer.email, payload.payment.amount);
},
});
```
--------------------------------
### Handle Webhook Events
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Implement business logic within the `onSubscriptionActive` handler in `src/app/api/webhook/route.ts` to manage subscription events.
```typescript
onSubscriptionActive: async (payload) => {
// Grant access to your product
// Update user database
// Send welcome email
},
```
--------------------------------
### Webhook Event Handler
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Handles incoming webhook events from Dodo Payments, verifies signatures, and dispatches to specific handler callbacks like `onSubscriptionActive` and `onPaymentSucceeded`.
```APIDOC
## `POST /api/webhook` — Webhook Event Handler
The `Webhooks` handler verifies the request signature using `webhookKey` and dispatches typed event payloads to named handler callbacks. The boilerplate includes `onSubscriptionActive` and `onPaymentSucceeded` handlers; additional event handlers can be added following the same pattern.
```typescript
// src/app/api/webhook/route.ts
import { Webhooks } from "@dodopayments/nextjs";
export const POST = Webhooks({
webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY!,
onSubscriptionActive: async (payload) => {
// payload contains subscriber and subscription metadata
console.log("Subscription activated:", payload);
// e.g., grant product access, write to database, send welcome email
await db.users.update({ customerId: payload.customer.id, plan: "active" });
},
onPaymentSucceeded: async (payload) => {
console.log("Payment succeeded:", payload);
// e.g., fulfil order, send receipt email
await sendReceiptEmail(payload.customer.email, payload.payment.amount);
},
});
```
```bash
# Testing locally with ngrok
ngrok http 3000
# Then set the ngrok URL as your webhook endpoint in the Dodo Payments Dashboard:
# https://.ngrok.io/api/webhook
```
```
--------------------------------
### POST /api/checkout — Session-Based Checkout
Source: https://context7.com/dodopayments/dodo-nextjs-minimal-boilerplate/llms.txt
Creates a dynamic checkout session from a JSON body containing a product cart and optional customer information. The response returns a checkout URL for client redirection.
```APIDOC
## POST /api/checkout — Session-Based Checkout
### Description
Creates a dynamic checkout session from a JSON body containing a product cart and optional pre-filled customer information. The response returns a `checkout_url` that the client redirects to. It uses the `Checkout` helper with `type: "session"`.
### Method
POST
### Endpoint
`/api/checkout`
### Request Body
- **product_cart** (array) - Required - An array of products in the cart.
- **product_id** (string) - Required - The ID of the product.
- **quantity** (number) - Required - The quantity of the product.
- **customer** (object) - Optional - Pre-filled customer information.
- **name** (string) - Optional - The customer's name.
- **email** (string) - Optional - The customer's email address.
### Request Example
```bash
curl -X POST "http://localhost:3000/api/checkout" \
-H "Content-Type: application/json" \
-d '{
"product_cart": [
{ "product_id": "pdt_001", "quantity": 1 }
],
"customer": {
"name": "Jane Smith",
"email": "jane@example.com"
}
}'
```
### Response
#### Success Response (200)
- **checkout_url** (string) - The generated checkout session URL.
#### Response Example
```json
{
"checkout_url": "https://checkout.dodopayments.com/session/sess_abc123..."
}
```
```
--------------------------------
### Pre-fill Customer Data
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Customize the `ProductCard.tsx` component by replacing placeholder values with actual customer data to pre-fill checkout forms.
```typescript
customer: {
name: "John Doe",
email: "john@example.com",
},
```
--------------------------------
### Update Customer Portal Link
Source: https://github.com/dodopayments/dodo-nextjs-minimal-boilerplate/blob/main/README.md
Modify the `Header.tsx` component to use the correct customer ID for linking to the customer portal.
```typescript
const CUSTOMER_ID = "cus_001"; // Replace with actual customer ID
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.