End-to-end demo app showing three billing models wired to Dodo Payments (test environment):
- One-time payments (credit pack)
- Recurring subscriptions
- Usage-based billing (pay-per-event)
Built with Next.js App Router, NextAuth, MongoDB, and Tailwind.
- Clone and install:
npm install
- Create
.env.local(see Environment variables) and fill required keys. - Run locally:
npm run devβ openhttp://localhost:3000
- Go to
Pricingβ pick a plan β complete Dodo test checkout β land onDashboard.
- User picks Credit Pack on
Pricing. - Backend calls
POST /api/create-paymentβ getspayment_linkfrom Dodo β redirect to checkout. - After success,
DashboardcallsPOST /api/verify-paymentto confirm and update the user in MongoDB. - Credits added: 10 credits per successful purchase.
- User picks a subscription plan.
- Backend calls
POST /api/create-subscriptionβpayment_linkβ redirect to checkout. - On return,
POST /api/verify-paymentconfirms and stores subscription status.
- User chooses the usage-based plan.
- Backend calls
POST /api/create-usage-subscription(marksmetadata.billing_type = usage_based). - Verification persists the Dodo
customer_id. - When features are used (e.g., image generation), the app sends usage events that accrue cost.
- Hook
useUsageTrackingposts toPOST /api/send-usage-event, which forwards usage to Dodo against the storedcustomer_id. - The dashboard reads current usage/cost via
POST /api/check-payment-status.
Example snippet:
import { useUsageTracking } from '@/hooks/useUsageTracking'
function ImageGenerator() {
const { trackUsage } = useUsageTracking()
async function generateImage() {
const image = await yourAPI.generate()
await trackUsage('image.generation', { resolution: '1024x1024' })
return image
}
}See src/components/examples/ImageGeneratorExample.tsx for a full example.
Create .env.local in the project root and provide the following:
Required for database and NextAuth:
MONGO_URIβ MongoDB connection stringNEXTAUTH_URLβ e.g.http://localhost:3000NEXTAUTH_SECRETβ random string for session/JWT encryption
Auth providers (enable at least one sign-in method):
RESEND_API_KEYβ for email sign-in via ResendFROM_EMAILβ sender email for Resend (e.g.[email protected])AUTH_GOOGLE_IDβ Google OAuth Client IDAUTH_GOOGLE_SECRETβ Google OAuth Client Secret
Dodo Payments (test environment):
DODO_PAYMENTS_API_KEYβ server-side secret key for Dodo test APINEXT_PUBLIC_APP_URLβ app base URL used in return URLs (defaulthttp://localhost:3000)
Notes:
- All server routes call
https://test.dodopayments.com. - For local dev, webhooks to
localhostare often blocked; use manual verification (/api/verify-payment).
npm install
npm run dev
# open http://localhost:3000Sign in from /auth/signin, visit Pricing, complete a test checkout, and review your status on Dashboard.
POST /api/create-paymentβ Create a one-time payment and get a Dodopayment_link.POST /api/create-subscriptionβ Create a recurring subscription and get apayment_link.POST /api/create-usage-subscriptionβ Create a usage-based subscription and get apayment_link.POST /api/send-usage-eventβ Forward a usage event for the current userβscustomer_id.POST /api/check-payment-statusβ Read persisted user payment and usage status.POST /api/verify-paymentβ Manually verify payment/subscription with Dodo (handy locally).POST /api/webhooks/paymentβ Receives Dodo webhooks (configure in production; optional locally).
Webhook signature verification is stubbed; add verification before going to production.
- Next.js App Router (TypeScript)
- NextAuth (JWT sessions, MongoDB adapter)
- MongoDB (native driver)
- Tailwind CSS
- Dodo Payments (test API)
Key files:
- Auth config:
auth.ts - DB client:
src/lib/mongo.ts - Payments/usage routes:
src/app/api/* - Dashboard:
src/app/dashboard/page.tsx - Pricing:
src/app/pricing/page.tsx
- Missing
MONGO_URI: the app will throw at startup β set.env.local. - 500 on payment routes: ensure
DODO_PAYMENTS_API_KEYis set. - Redirect loops after sign-in: check
NEXTAUTH_URLandNEXTAUTH_SECRET. - No credits after purchasing Credit Pack: use
POST /api/verify-payment(local), or configure webhooks in prod. - Usage not reflected: ensure
customer_idis saved byverify-paymentand your feature callstrackUsage.
Follow these paths end-to-end in test mode:
- Credit Pack β Pay β Dashboard shows +10 credits
- Subscription β Pay β Dashboard shows active subscription
- Usage-based β Pay β Generate image β Usage and cost update on Dashboard
- Dodo Payments Docs:
https://docs.dodopayments.com