> ## Documentation Index
> Fetch the complete documentation index at: https://flowglad.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup

> Setup instructions for Flowglad Next.js, React, and Server SDKs. Read [choosing the right SDK](/sdks/introduction#choosing-the-right-sdk) first, then follow the framework-specific steps below.

<Tabs>
  <Tab title="Next.js">
    ## Installation

    <CodeGroup>
      ```bash npm theme={null}
      npm install @flowglad/nextjs
      ```

      ```bash yarn theme={null}
      yarn add @flowglad/nextjs
      ```

      ```bash bun theme={null}
      bun add @flowglad/nextjs
      ```
    </CodeGroup>

    ## 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:

    ```bash .env theme={null}
    FLOWGLAD_SECRET_KEY="sk_test_..."
    ```

    ### 2. Create Server Client

    Create a Flowglad server factory function in a shared file, eg. `lib/flowglad.ts`:

    <CodeGroup>
      ```ts Generic theme={null}
      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,
            }
          },
        })
      }
      ```

      ```ts Example: Better Auth theme={null}
      import { FlowgladServer } from '@flowglad/nextjs/server'
      import { auth } from '@/utils/auth'
      import { headers } from 'next/headers'

      export const flowglad = (customerExternalId: string) => {
        return new FlowgladServer({
          customerExternalId,
          getCustomerDetails: async (customerExternalId) => {
            const session = await auth.api.getSession({
              headers: await headers(),
            })
            if (!session?.user) {
              throw new Error('User not authenticated')
            }
            return {
              email: session.user.email || '',
              name: session.user.name || ''
            }
          },
        })
      }
      ```

      ```ts Example: Supabase Auth theme={null}
      import { FlowgladServer } from '@flowglad/nextjs/server'
      import { createClient } from '@/utils/supabase/server'

      export const flowglad = (customerExternalId: string) => {
        return new FlowgladServer({
          customerExternalId,
          getCustomerDetails: async (customerExternalId) => {
            const supabase = await createClient()
            const { data: { user } } = await supabase.auth.getUser()
            if (!user) {
              throw new Error('User not authenticated')
            }
            return {
              email: user.email || '',
              name: user.user_metadata.name || user.email || ''
            }
          },
        })
      }
      ```

      ```ts Example: B2B (Organization-based) theme={null}
      import { FlowgladServer } from '@flowglad/nextjs/server'

      export const flowglad = (organizationId: string) => {
        // For B2B apps: organizationId is ID from YOUR app's database
        return new FlowgladServer({
          customerExternalId: organizationId,
          getCustomerDetails: async (customerExternalId) => {
            // Fetch organization details from YOUR database using YOUR org ID
            const org = await db.organizations.findOne({ id: customerExternalId })
            if (!org) {
              throw new Error('Organization not found')
            }
            return {
              email: org.billingEmail || org.ownerEmail,
              name: org.name,
            }
          },
        })
      }
      ```
    </CodeGroup>

    <Note>
      **Important:** `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 `customerExternalId`\
      **B2B apps:** Pass `organization.id` or `team.id` as `customerExternalId`
    </Note>

    <Info>
      Flowglad integrates seamlessly with your auth provider. Read more about auth options [here](/sdks/auth).
    </Info>

    ### 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 the [`useBilling` hook](/sdks/react#usebilling-hook) on your frontend. It should handle requests at `/api/flowglad/...`

    <Tabs>
      <Tab title="Next.js App Router">
        ```ts title="app/api/flowglad/[...path]/route.ts" theme={null}
        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
          },
        })
        ```
      </Tab>

      <Tab title="Next.js Pages Router">
        ```ts title="pages/api/flowglad/[...path].ts" theme={null}
        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
          },
        })
        ```
      </Tab>

      <Tab title="Express">
        ```ts title="server.ts" theme={null}
        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
            },
          })
        )
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```ts title="server.ts" theme={null}
        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,
            }
          )
        }
        ```
      </Tab>
    </Tabs>

    ### 4. Wrap Your App with FlowgladProvider

    <Tabs>
      <Tab title="Next.js App Router">
        ```tsx title="app/layout.tsx" theme={null}
        import { FlowgladProvider } from '@flowglad/nextjs'

        export default function RootLayout({ children }) {
          return (
            <html>
              <body>
                <FlowgladProvider>
                  {children}
                </FlowgladProvider>
              </body>
            </html>
          )
        }
        ```
      </Tab>

      <Tab title="Next.js Pages Router">
        ```tsx title="pages/_app.tsx" theme={null}
        import { FlowgladProvider } from '@flowglad/nextjs'

        export default function App({ Component, pageProps }) {
          return (
            <FlowgladProvider>
              <Component {...pageProps} />
            </FlowgladProvider>
          )
        }
        ```
      </Tab>

      <Tab title="Vite + React">
        ```tsx title="src/App.tsx" theme={null}
        import { FlowgladProvider } from '@flowglad/react'

        export default function App({ children }) {
          return (
            <FlowgladProvider>
              {children}
            </FlowgladProvider>
          )
        }
        ```
      </Tab>
    </Tabs>

    ### 5. Use the Billing Hook

    <Tabs>
      <Tab title="Next.js">
        ```tsx theme={null}
        "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>
          )
        }
        ```
      </Tab>

      <Tab title="Vite + React">
        ```tsx theme={null}
        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>
          )
        }
        ```
      </Tab>
    </Tabs>

    <Info>Read more about the Flowglad Next.js SDK at the [Next.js documentation page](/sdks/nextjs)</Info>
  </Tab>

  <Tab title="React">
    ## Installation

    <CodeGroup>
      ```bash npm theme={null}
      npm install @flowglad/react @flowglad/server
      ```

      ```bash yarn theme={null}
      yarn add @flowglad/react @flowglad/server
      ```

      ```bash bun theme={null}
      bun add @flowglad/react @flowglad/server
      ```
    </CodeGroup>

    <Note>
      **Note:** This package requires `@flowglad/server` to be set up on your backend. See the Server tab or [Server SDK documentation](/sdks/server) for setup instructions.
    </Note>

    ## Quick Start

    ### 1. Wrap Your App with FlowgladProvider

    ```tsx theme={null}
    import { FlowgladProvider } from '@flowglad/react'

    export default function App({ children }) {
      return (
        <FlowgladProvider
          requestConfig={{
            headers: {
              // Add custom headers if needed
            },
          }}
        >
          {children}
        </FlowgladProvider>
      )
    }
    ```

    ### 2. Use the useBilling Hook

    ```tsx theme={null}
    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>
    }
    ```

    <Info>Read more about the Flowglad React SDK at the [React documentation page](/sdks/react)</Info>
  </Tab>

  <Tab title="Server">
    ## Installation

    <CodeGroup>
      ```bash npm theme={null}
      npm install @flowglad/server
      ```

      ```bash yarn theme={null}
      yarn add @flowglad/server
      ```

      ```bash bun theme={null}
      bun add @flowglad/server
      ```
    </CodeGroup>

    ## Quick Start

    ### 1. Set Up Environment Variables

    ```bash .env theme={null}
    FLOWGLAD_SECRET_KEY="sk_test_..."
    ```

    ### 2. Create a FlowgladServer Factory Function

    <CodeGroup>
      ```ts Generic theme={null}
      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()
      ```

      ```ts Example: Better Auth theme={null}
      import { FlowgladServer } from '@flowglad/server'
      import { auth } from '@/utils/auth'

      export const flowglad = (customerExternalId: string) => {
        return new FlowgladServer({
          customerExternalId,
          getCustomerDetails: async (customerExternalId) => {
            const session = await auth.api.getSession()
            if (!session?.user) {
              throw new Error('User not authenticated')
            }
            return {
              email: session.user.email || '',
              name: session.user.name || ''
            }
          },
        })
      }
      ```

      ```ts Example: Supabase Auth theme={null}
      import { FlowgladServer } from '@flowglad/server'
      import { createClient } from '@/utils/supabase/server'

      export const flowglad = (customerExternalId: string) => {
        return new FlowgladServer({
          customerExternalId,
          getCustomerDetails: async (customerExternalId) => {
            const supabase = await createClient()
            const { data: { user } } = await supabase.auth.getUser()
            if (!user) {
              throw new Error('User not authenticated')
            }
            return {
              email: user.email || '',
              name: user.user_metadata.name || user.email || ''
            }
          },
        })
      }
      ```

      ```ts Example: B2B (Organization-based) theme={null}
      import { FlowgladServer } from '@flowglad/server'

      export const flowglad = (organizationId: string) => {
        // For B2B apps: organizationId is ID from YOUR app's database
        return new FlowgladServer({
          customerExternalId: organizationId,
          getCustomerDetails: async (customerExternalId) => {
            // Fetch organization details from YOUR database using YOUR org ID
            const org = await db.organizations.findOne({ id: customerExternalId })
            if (!org) {
              throw new Error('Organization not found')
            }
            return {
              email: org.billingEmail || org.ownerEmail,
              name: org.name,
            }
          },
        })
      }
      ```
    </CodeGroup>

    <Note>
      **Important:** `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 `customerExternalId`\
      **B2B apps:** Pass `organization.id` or `team.id` as `customerExternalId`
    </Note>

    ### 3. 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 the [`useBilling` hook](/sdks/react#usebilling-hook) on your frontend. It should handle requests at "/api/flowglad/..."

    <Tabs>
      <Tab title="Next.js App Router">
        ```ts title="app/api/flowglad/[...path]/route.ts" theme={null}
        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
          },
        })
        ```
      </Tab>

      <Tab title="Next.js Pages Router">
        ```ts title="pages/api/flowglad/[...path].ts" theme={null}
        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
          },
        })
        ```
      </Tab>

      <Tab title="Express">
        ```ts title="server.ts" theme={null}
        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
            },
          })
        )
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```ts title="server.ts" theme={null}
        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,
            }
          )
        }
        ```
      </Tab>
    </Tabs>

    ### 4. Call Server Methods

    ```ts theme={null}
    // 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',
    })
    ```

    <Info>Read more about the Flowglad Server SDK at the [Server documentation page](/sdks/server)</Info>
  </Tab>
</Tabs>
