Core Concepts
The Data Flow
In a standard Flowglad integration, data flows from Flowglad’s API, to your server, and then from your server to your React frontend. The result is that you no longer need to maintain glue code that syncs the data in your application with the data in Flowglad’s servers. Instead of this webhook approach, Flowglad is designed to be reactive.The Read Flow
The Write Flow
+Similarly, mutations flow in reverse: propagating from your frontend, to your server, to our server. This allows us to deliver the data door-to-door to your frontend code, while ensuring that all the data is scoped to the specific customer.The Lifecycle
Every Flowglad workflow in your app should start with an attempt to find or create the customer, and then either take an action or check the state.Authentication Coupling
On your backend, Flowglad couples closely with your authentication. Workflows that involve Flowglad should first consider who the customer is that you are making requests for. All customers in your database should have corresponding customer records in Flowglad, regardless of whether they are paying. To achieve this, start by adding a call to /create-customer in your app’s account creation flow. Flowglad manages the billing state for all your customers, including customers on your free plans. That management includes managing which features your customers can access and what balances they have on your product’s usage meters.Account Creation Flow
When you refer to your customers with Flowglad, you do so using your customer id, rather than ours. If your customers are individuals, use theiruser.id from your database. If your customers are businesses, teams, or other organizations, you can use their organization.id.
Integrating Flowglad does not require you to make any schema changes to your database. You do not need to store a
flowglad_customer_id or flowglad_price_id.Implementation Plan
Implementing Flowglad on your backend will consist of 3 steps (feel free to feed this to AI):- Add Flowglad customer creation to your product’s account creation flow
- Call POST /customers to create the customer
-
Create a server route at
/api/flowglad/:subroutethat is publicly accessible and authenticated using your existing server-side authentication logic. Your frontend will send requests to this route via the @flowglad/react SDK. -
Implement a set of helper functions in your backend to handle common actions:
findOrCreateCustomerBilling({ name: string, externalId: string, email: string }): call GET /customers/:externalId/billing. If you receive a 404, call POST /customers to create the customercheckFeatureAccess(slug: string, customerBilling: <GET /customers/:externalId response>):- gets
experimental.featureItemspayload in the firstcurrentSubscriptionin the customer billing response - returns true if a feature is present where
feature.type=="toggle" && feature.slug == slug - returns false otherwise
- gets
- if you plan to track usage in real time:
checkUsageBalance(slug: string, customerBilling: <GET /customers/:externalId response>):- gets
experimental.usageMeterBalancesin the firstcurrentSubscriptionin the customer billing response - finds the
usageMeterBalancewhereusageMeterBalance.slug == slug - returns
{ availableBalance: number }if the usageMeterBalance is found, usingusageMeterBalance.availableBalance - returns
nullif not found
- gets
Authenticate and Derive the Requesting Customer
Every server-originated Flowglad call needs the customer scoped using your ids. TheFlowgladServer class uses a scoped pattern:
- Create a factory function that takes
customerExternalId(from your app’s database, not Flowglad’s) and returns aFlowgladServerinstance - Provide a
getCustomerDetailsfunction that fetches customer name and email from your database - Use the scoped instance:
await flowglad(customerExternalId).getBilling()
customerExternalId is the ID from your app’s database (e.g., user.id or organization.id), not Flowglad’s customer ID.
B2C apps: Use user.id as customerExternalIdB2B apps: Use
organization.id or team.id as customerExternalId
When you are not using our SDKs, replicate the same logic:
- Extract the
customerExternalIdfrom your authentication (user ID for B2C, organization ID for B2B) - this is your app’s ID, not Flowglad’s - Fetch customer details (name, email) from your database
- Pass
customerExternalId(your app’s ID) and customer details to every Flowglad API call
Implement the Sub-routes
Expose a single authenticated route such as/api/flowglad/:subroute. Each subroute matches a FlowgladActionKey (see packages/shared/src/types.ts) and must accept a POST, even for reads—the React SDK always sends POST requests and expects { data, error? } in the response body.
POST /customers/billing
- use your authentication logic to derive the customer making the request from your frontend
{ name: string, externalId: string, email: string }, where theemailis the email address associated with the owner of the account andexternalIdis the id of the customer in your system - use the
findOrCreateCustomerBillinghelper to get the customer billing data, return it inside{ data: billing }, and optionally include the computed helpers (checkFeatureAccess,checkUsageBalance,getProduct,getPrice) before sending the JSON back to the client.
- accept
{ successUrl, cancelUrl, outputMetadata?, outputName?, quantity?, priceId? | priceSlug? }. - if the frontend sent a
priceSlug, look it up from the catalog you received in/customers/billingand substitute the resolvedpriceIdbefore calling POST /checkout-sessions. - always include
customerExternalId(your id) in the request body so Flowglad scopes the checkout correctly.
- payload mirrors the create endpoint but without price fields, plus an optional
targetSubscriptionId. - send
type: "add_payment_method"to POST /checkout-sessions. - respond with the
{ checkoutSession: { id, url } }object from Flowglad. The React SDK will optionally redirect using theurl.
- requires
{ targetSubscriptionId, priceId, successUrl, cancelUrl }. - send
type: "activate_subscription"to POST /checkout-sessions so the Flowglad dashboard knows to attach the subscription after payment.
- expect
{ id, cancellation }wherecancellationis one of:{ timing: "at_end_of_current_billing_period" }{ timing: "at_future_date", endDate }{ timing: "immediately" }
- fetch the subscription first and confirm that
subscription.customerIdmatches the requesting customer’s Flowglad id before calling POST /subscriptions/:id/cancel. If they do not match, return403.