Skip to main content
NPM Package: @flowglad/express

Overview

The Express SDK provides middleware and route handlers for integrating Flowglad into your Express.js applications. It works seamlessly with the Flowglad Server SDK to handle billing operations.

Installation

npm install @flowglad/express

Quick Start

1. Set Up Environment Variables

.env
FLOWGLAD_SECRET_KEY="sk_test_..."

2. Create Flowglad Server Factory Function

src/utils/flowglad.ts
import { FlowgladServer } from '@flowglad/express'

// Factory that creates a FlowgladServer for a specific customer
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 (externalId) => {
      // Fetch customer details from YOUR database using YOUR app's ID
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

// Factory that builds a FlowgladServer for each request
export const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  const userId = req.user?.id
  if (!userId) {
    throw new Error('User not authenticated')
  }
  return flowglad(userId)
}

3. Add Routes to Your Express App

import express from 'express'
import { createFlowgladExpressRouter } from '@flowglad/express'
import { flowgladServerConstructor } from './utils/flowglad'

const app = express()

// Mount Flowglad routes at /api/flowglad
app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({
    flowgladServerConstructor,
  })
)

app.listen(3000, () => {
  console.log('Server running on port 3000')
})

Key Features

  • Express Router: Pre-configured router for easy mounting
  • Route Handler: Flexible handler for custom routing
  • Request Context: Automatic customer context from requests
  • Error Handling: Built-in error handling for billing operations
  • Type Safety: Full TypeScript support

API Reference

createFlowgladExpressRouter

Creates an Express router with all Flowglad routes pre-configured.

Parameters

interface CreateFlowgladExpressRouterOptions {
  flowgladServerConstructor: (
    req: Request
  ) => Promise<FlowgladServer> | FlowgladServer
  middleware?: RequestHandler[]
  beforeRequest?: () => Promise<void>
  afterRequest?: () => Promise<void>
  onError?: (error: unknown) => void
}

Returns

  • Router - An Express router instance

Example

import express, { type Request } from 'express'
import { createFlowgladExpressRouter } from '@flowglad/express'
import { FlowgladServer } from '@flowglad/server'
import { requireAuth } from './middleware/auth'

const app = express()

const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  const user = req.user as { id: string } | null
  if (!user) {
    throw new Error('User not authenticated')
  }
  return flowglad(user.id)
}

// Mount at /api/flowglad
app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({
    middleware: [requireAuth],
    flowgladServerConstructor,
  })
)

// Or mount at a different path
app.use(
  '/billing',
  createFlowgladExpressRouter({ flowgladServerConstructor })
)

createExpressRouteHandler

Creates a route handler function for custom routing setups.

Parameters

interface CreateFlowgladExpressRouteHandlerOptions {
  flowgladServer: FlowgladServer
  beforeRequest?: () => Promise<void>
  afterRequest?: () => Promise<void>
  onError?: (error: unknown) => void
}

Returns

  • RequestHandler - An Express request handler

Example

import express from 'express'
import { createExpressRouteHandler } from '@flowglad/express'
import { FlowgladServer } from '@flowglad/server'

const app = express()

const flowgladServer = new FlowgladServer({ /* ... */ })
const flowgladHandler = createExpressRouteHandler({ flowgladServer })

// Handle all HTTP methods
app.all('/api/flowglad/*', flowgladHandler)

// Or handle specific methods
app.get('/api/flowglad/*', flowgladHandler)
app.post('/api/flowglad/*', flowgladHandler)

Integration with Authentication

Passport.js Example

src/utils/flowglad.ts
import { FlowgladServer } from '@flowglad/server'
import type { Request } from 'express'

const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

export const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  const user = req.user as { id: string } | undefined
  if (!user) {
    throw new Error('User not authenticated')
  }
  return flowglad(user.id)
}

JWT Auth Example

src/utils/flowglad.ts
import { FlowgladServer } from '@flowglad/server'
import type { Request } from 'express'
import jwt from 'jsonwebtoken'

const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

export const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  const token = req.headers.authorization?.replace('Bearer ', '')
  if (!token) {
    throw new Error('User not authenticated')
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as {
      userId: string
    }
    return flowglad(decoded.userId)
  } catch (error) {
    throw new Error('Invalid token')
  }
}

Session-Based Auth Example

src/utils/flowglad.ts
import { FlowgladServer } from '@flowglad/server'
import type { Request } from 'express'

const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

export const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  if (!req.session?.userId) {
    throw new Error('User not authenticated')
  }
  return flowglad(req.session.userId)
}

Complete Example

Here’s a full Express application with Flowglad integration:
src/index.ts
import express, { type Request } from 'express'
import session from 'express-session'
import { createFlowgladExpressRouter } from '@flowglad/express'
import { FlowgladServer } from '@flowglad/server'

const app = express()

// Middleware
app.use(express.json())
app.use(
  session({
    secret: process.env.SESSION_SECRET!,
    resave: false,
    saveUninitialized: false,
  })
)

// Create Flowglad server factory function
const flowglad = (customerExternalId: string) => {
  // customerExternalId is the ID from YOUR app's database, NOT Flowglad's customer ID
  return new FlowgladServer({
    customerExternalId,
    getCustomerDetails: async (externalId) => {
      const user = await db.users.findOne({ id: externalId })
      return {
        email: user.email,
        name: user.name,
      }
    },
  })
}

// Create Flowglad server constructor
const flowgladServerConstructor = (req: Request) => {
  // Extract customerExternalId from your auth/session
  // This should be YOUR app's user/organization ID, NOT Flowglad's customer ID
  if (!req.session?.userId) {
    throw new Error('User not authenticated')
  }
  return flowglad(req.session.userId)
}

// Mount Flowglad routes
app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({ flowgladServerConstructor })
)

// Your other routes
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' })
})

const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

Middleware Configuration

CORS

If you need CORS support, add it before the Flowglad routes:
import cors from 'cors'

app.use(
  '/api/flowglad',
  cors({
    origin: process.env.FRONTEND_URL,
    credentials: true,
  })
)

app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({ flowgladServerConstructor })
)

Custom Middleware

Add custom middleware before the Flowglad routes:
import { requireAuth } from './middleware/auth'

// Protect Flowglad routes with authentication
app.use('/api/flowglad', requireAuth)
app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({ flowgladServerConstructor })
)

Error Handling

The Express SDK includes built-in error handling, but you can add custom error handlers:
app.use(
  '/api/flowglad',
  createFlowgladExpressRouter({ flowgladServerConstructor })
)

// Custom error handler
app.use((err, req, res, next) => {
  console.error('Flowglad error:', err)
  res.status(500).json({
    error: 'Internal server error',
    message: process.env.NODE_ENV === 'development' ? err.message : undefined,
  })
})

Example Project

For a complete working example, see our Express playground project.

Next Steps