- Next.js
- React
- Server
Installation
Copy
Ask AI
npm install @flowglad/nextjs
Requirements
- React 18 or 19
- Next.js 14 or 15
Quick Start
1. Set Up Environment Variables
Add your Flowglad API key to your environment:.env
Copy
Ask AI
FLOWGLAD_SECRET_KEY="sk_test_..."
2. Create Server Client
Create a Flowglad server factory function in a shared file, eg.lib/flowglad.ts:Copy
Ask AI
import { FlowgladServer } from '@flowglad/nextjs/server'
export const flowglad = (customerExternalId: string) => {
// customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
return new FlowgladServer({
customerExternalId,
getCustomerDetails: async (customerExternalId) => {
// Fetch customer details from YOUR database using YOUR app's ID
const user = await db.users.findOne({ id: customerExternalId })
if (!user) {
throw new Error('Customer not found')
}
return {
email: user.email,
name: user.name,
}
},
})
}
Important:
B2B apps: Pass
customerExternalId is the ID from your app’s database (e.g., user.id or organization.id), not Flowglad’s customer ID.B2C apps: Pass user.id as customerExternalIdB2B apps: Pass
organization.id or team.id as customerExternalIdFlowglad integrates seamlessly with your auth provider. Read more about auth options here.
3. Create API Route Handler
Create a route handler to handle Flowglad API requests from your frontend. The Server SDK provides route handler constructors that enable your client to communicate with your server, allowing you to load billing and feature access data via theuseBilling hook on your frontend. It should handle requests at /api/flowglad/...- Next.js App Router
- Next.js Pages Router
- Express
- Other Frameworks
app/api/flowglad/[...path]/route.ts
Copy
Ask AI
import { nextRouteHandler } from '@flowglad/nextjs/server'
import { flowglad } from '@/lib/flowglad'
import { customerIdFromRequest } from '@/lib/auth'
export const { GET, POST } = nextRouteHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
pages/api/flowglad/[...path].ts
Copy
Ask AI
import { pagesRouteHandler } from '@flowglad/nextjs/server'
import { flowglad } from '@/lib/flowglad'
import { customerIdFromRequest } from '@/lib/auth'
export default pagesRouteHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
server.ts
Copy
Ask AI
import express from 'express'
import { expressRouter } from '@flowglad/server/express'
import { flowglad } from './lib/flowglad'
import { customerIdFromRequest } from './lib/auth'
const app = express()
app.use(
'/api/flowglad',
expressRouter({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
)
server.ts
Copy
Ask AI
import { requestHandler } from '@flowglad/server'
import { flowglad } from './lib/flowglad'
import { customerIdFromRequest } from './lib/auth'
import type { HTTPMethod } from '@flowglad/shared'
const flowgladHandler = requestHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
// Example: Hono, Cloudflare Workers, Elysia, etc.
// Adapt this pattern to your framework
async function handleFlowgladRequest(request: Request): Promise<Response> {
const url = new URL(request.url)
const path = url.pathname
.replace('/api/flowglad/', '')
.split('/')
.filter((segment) => segment !== '')
const result = await flowgladHandler(
{
path,
method: request.method as HTTPMethod,
query:
request.method === 'GET'
? Object.fromEntries(url.searchParams)
: undefined,
body:
request.method !== 'GET'
? await request.json().catch(() => ({}))
: undefined,
},
request
)
return Response.json(
{
error: result.error,
data: result.data,
},
{
status: result.status,
}
)
}
4. Wrap Your App with FlowgladProvider
- Next.js App Router
- Next.js Pages Router
- Vite + React
app/layout.tsx
Copy
Ask AI
import { FlowgladProvider } from '@flowglad/nextjs'
export default function RootLayout({ children }) {
return (
<html>
<body>
<FlowgladProvider loadBilling={true}>
{children}
</FlowgladProvider>
</body>
</html>
)
}
pages/_app.tsx
Copy
Ask AI
import { FlowgladProvider } from '@flowglad/nextjs'
export default function App({ Component, pageProps }) {
return (
<FlowgladProvider loadBilling={true}>
<Component {...pageProps} />
</FlowgladProvider>
)
}
src/App.tsx
Copy
Ask AI
import { FlowgladProvider } from '@flowglad/react'
export default function App({ children }) {
return (
<FlowgladProvider loadBilling={true}>
{children}
</FlowgladProvider>
)
}
5. Use the Billing Hook
- Next.js
- Vite + React
Copy
Ask AI
"use client"
import { useBilling } from '@flowglad/nextjs'
export default function BillingPage() {
const { checkFeatureAccess, createCheckoutSession } = useBilling()
if (!checkFeatureAccess) {
return <div>Loading...</div>
}
if (checkFeatureAccess('premium_feature')) {
return <div>You have access to premium features!</div>
}
return (
<button
onClick={() =>
createCheckoutSession({
priceSlug: 'pro_plan',
successUrl: window.location.href,
cancelUrl: window.location.href,
autoRedirect: true,
})
}
>
Upgrade to Premium
</button>
)
}
Copy
Ask AI
import { useBilling } from '@flowglad/react'
export default function BillingPage() {
const { checkFeatureAccess, createCheckoutSession } = useBilling()
if (!checkFeatureAccess) {
return <div>Loading...</div>
}
if (checkFeatureAccess('premium_feature')) {
return <div>You have access to premium features!</div>
}
return (
<button
onClick={() =>
createCheckoutSession({
priceSlug: 'pro_plan',
successUrl: window.location.href,
cancelUrl: window.location.href,
autoRedirect: true,
})
}
>
Upgrade to Premium
</button>
)
}
Read more about the Flowglad Next.js SDK at the Next.js documentation page
Installation
Copy
Ask AI
npm install @flowglad/react @flowglad/server
Note: This package requires
@flowglad/server to be set up on your backend. See the Server tab or Server SDK documentation for setup instructions.Quick Start
1. Wrap Your App with FlowgladProvider
Copy
Ask AI
import { FlowgladProvider } from '@flowglad/react'
export default function App({ children }) {
return (
<FlowgladProvider
loadBilling={true}
requestConfig={{
headers: {
// Add custom headers if needed
},
}}
>
{children}
</FlowgladProvider>
)
}
2. Use the useBilling Hook
Copy
Ask AI
import { useBilling } from '@flowglad/react'
export default function BillingPage() {
const { checkFeatureAccess, customer, paymentMethods } = useBilling()
if (!checkFeatureAccess) {
return <div>Loading...</div>
}
if (checkFeatureAccess('premium_feature')) {
return <div>You have access!</div>
}
return <div>Please upgrade</div>
}
Read more about the Flowglad React SDK at the React documentation page
Installation
Copy
Ask AI
npm install @flowglad/server
Quick Start
1. Set Up Environment Variables
.env
Copy
Ask AI
FLOWGLAD_SECRET_KEY="sk_test_..."
2. Create a FlowgladServer Factory Function
Copy
Ask AI
import { FlowgladServer } from '@flowglad/server'
export const flowglad = (customerExternalId: string) => {
// customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
return new FlowgladServer({
customerExternalId,
getCustomerDetails: async (customerExternalId) => {
// Fetch customer details from YOUR database using YOUR app's ID
const user = await db.users.findOne({ id: customerExternalId })
if (!user) {
throw new Error('Customer not found')
}
return {
email: user.email,
name: user.name,
}
},
})
}
// Usage:
// Pass YOUR app's user/organization ID, not Flowglad's customer ID
const billing = await flowglad(userId).getBilling()
Important:
B2B apps: Pass
customerExternalId is the ID from your app’s database (e.g., user.id or organization.id), not Flowglad’s customer ID.B2C apps: Pass user.id as customerExternalIdB2B apps: Pass
organization.id or team.id as customerExternalId3. Mount Flowglad Route Handler
Create a route handler to handle Flowglad API requests from your frontend. The Server SDK provides route handler constructors that enable your client to communicate with your server, allowing you to load billing and feature access data via theuseBilling hook on your frontend. It should handle requests at “/api/flowglad/…“- Next.js App Router
- Next.js Pages Router
- Express
- Other Frameworks
app/api/flowglad/[...path]/route.ts
Copy
Ask AI
import { nextRouteHandler } from '@flowglad/nextjs/server'
import { flowglad } from '@/lib/flowglad'
import { customerIdFromRequest } from '@/lib/auth'
export const { GET, POST } = nextRouteHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
pages/api/flowglad/[...path].ts
Copy
Ask AI
import { pagesRouteHandler } from '@flowglad/nextjs/server'
import { flowglad } from '@/lib/flowglad'
import { customerIdFromRequest } from '@/lib/auth'
export default pagesRouteHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
server.ts
Copy
Ask AI
import express from 'express'
import { expressRouter } from '@flowglad/server/express'
import { flowglad } from './lib/flowglad'
import { customerIdFromRequest } from './lib/auth'
const app = express()
app.use(
'/api/flowglad',
expressRouter({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
)
server.ts
Copy
Ask AI
import { requestHandler } from '@flowglad/server'
import { flowglad } from './lib/flowglad'
import { customerIdFromRequest } from './lib/auth'
import type { HTTPMethod } from '@flowglad/shared'
const flowgladHandler = requestHandler({
flowglad,
getCustomerExternalId: async (req) => {
const externalId = await customerIdFromRequest(req)
if (!externalId) {
throw new Error('Unable to determine customer external ID')
}
return externalId
},
})
// Example: Hono, Cloudflare Workers, Elysia, etc.
// Adapt this pattern to your framework
async function handleFlowgladRequest(request: Request): Promise<Response> {
const url = new URL(request.url)
const path = url.pathname
.replace('/api/flowglad/', '')
.split('/')
.filter((segment) => segment !== '')
const result = await flowgladHandler(
{
path,
method: request.method as HTTPMethod,
query:
request.method === 'GET'
? Object.fromEntries(url.searchParams)
: undefined,
body:
request.method !== 'GET'
? await request.json().catch(() => ({}))
: undefined,
},
request
)
return Response.json(
{
error: result.error,
data: result.data,
},
{
status: result.status,
}
)
}
4. Call Server Methods
Copy
Ask AI
// Fetch billing details (customers, subscriptions, invoices, etc.)
// Pass YOUR app's user/organization ID, not Flowglad's customer ID
const billing = await flowglad(userId).getBilling()
// Ensure the Flowglad customer exists
const customer = await flowglad(userId).findOrCreateCustomer()
// Create a hosted checkout session
const checkoutSession = await flowglad(userId).createCheckoutSession({
priceSlug: 'pro_plan',
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/cancel',
})
// Check feature access for gating premium functionality
const hasPremium = billing.checkFeatureAccess('premium_feature')
// Record metered usage with price (for billing)
await flowglad(userId).createUsageEvent({
amount: 1,
priceSlug: 'usage_price_slug',
subscriptionId: 'subscription_id',
transactionId: 'idempotency-key',
})
// Record metered usage without price (for tracking only)
await flowglad(userId).createUsageEvent({
amount: 1,
usageMeterSlug: 'api_calls',
subscriptionId: 'subscription_id',
transactionId: 'idempotency-key',
})
Read more about the Flowglad Server SDK at the Server documentation page