Skip to main content
Startups face unexpected setbacks when implementing usage based pricing. Flowglad has designed usage based pricing to abstract away as much complexity as possible.

The Usage Data Model

At Flowglad, we’ve designed a flexible system to help you implement usage-based billing. Here’s a breakdown of the key components and how they work together. Think of it like measuring water consumption:
  1. Usage Meters: This is the central measuring device. For every type of usage you want to track (e.g., API calls, data storage, active users), you’ll create a Usage Meter. It’s like installing a specific water meter for your main water line, another for your garden hose, etc. Each meter has an Aggregation Type that determines how usage is calculated.
  2. Prices (Usage Type): Once you have a meter, you need to define how much to charge for what it measures. A Price of type “Usage” links directly to a Usage Meter. It sets the cost per unit of usage (e.g., 0.01perAPIcall,0.01 per API call, 5 per GB of storage). Multiple prices can be associated with a single usage meter, allowing for different pricing tiers or plans.
  3. Subscriptions: When a customer signs up for a product or service that has usage-based components, they are subscribed to one of these “Usage” Prices. This links the customer to the specific way their consumption will be measured and billed.
  4. Usage Events: These are the individual records of consumption. Every time a customer performs a billable action (e.g., makes an API call, an active user logs in), a Usage Event is recorded. Each event is tied to:
    • The Customer
    • Their Subscription
    • The relevant Usage Meter (either directly, or through a Price for billing)
How Usage is Aggregated Usage Meters collect all the Usage Events and aggregate them based on the chosen Aggregation Type for a billing period:
  • Sum: This is the simplest model. It adds up the amount from all usage events. For example, if a customer makes 100 API calls, and each Usage Event has an amount of 1, the total aggregated usage is 100. This is ideal for things like tokens consumed, messages sent, or data processed.
  • Count Distinct Properties: This model counts the unique values of a specific property within the Usage Events. For instance, to bill for “monthly active users,” you’d send a Usage Event each time a user is active, including a userId in the properties field. The meter would then count the number of unique userIds within the billing period. This is great for MAUs, unique workspace users, etc.
By default, Flowglad charges for aggregated usage at the end of the billing period. This ensures all consumption within that period is accurately captured before invoicing.

Setting Up and Using Usage-Based Billing

Here’s how to get started with tracking and billing for usage:

Step 1: Create a Usage Meter

  1. Navigate to the Pricing Models page in your dashboard and select the pricing model you would like to create the usage meter in.
  2. Click “Create Usage Meter.”
  3. Give your meter a descriptive name (e.g., “API Calls,” “Active Users”).
  4. Select the Aggregation Type:
    • Sum: To add up values from usage events.
    • Count Distinct Properties: To count unique property values.
  5. Save the meter. You’ll need its id for the next step.

Step 2: Create a Usage Price

  1. Go to “Products” and select the Product this usage component will belong to, or create a new one.
  2. Within the Product, go to the “Prices” section and click “Create Price.”
  3. Set the Type to “Usage”.
  4. Fill in the price details (name, unit price, currency, interval, etc.).
  5. Crucially, select the Usage Meter you created in Step 1 from the Usage Meter dropdown. This links this price to that specific meter.

Step 3: Report Usage Events

Reporting usage is done via API calls from your backend. This is to ensure data integrity and security, as you’ll be verifying and sending financial data. You’ll use the FlowgladServer.createUsageEvent method. You can create usage events in two ways: with a price (for tracking usage with billing) or with a usage meter directly (for tracking usage without billing).

Creating Usage Events with a Price

If you’ve created a usage price in Step 2, you can reference it when creating usage events:
import { FlowgladServer } from '@flowglad/server'; // Adjust import based on your setup

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

export const reportUsage = async (data: {
  customerExternalId: string; // The customer ID from YOUR app's database, NOT Flowglad's customer ID
  subscriptionId: string;   // The ID of the usage subscription
  priceSlug: string;        // The slug of the specific usage price
  amount: number;           // The quantity of usage (for 'sum' aggregation)
  transactionId: string;    // A unique ID from your system to ensure idempotency
  usageDate?: Date;         // Optional: Defaults to now. Date usage occurred.
  properties?: Record<string, any>; // Required for 'count_distinct_properties' meters
                                   // e.g., { "userId": "user_123" }
}) => {
  try {
    const usageEventPayload = {
      subscriptionId: data.subscriptionId,
      priceSlug: data.priceSlug,
      amount: data.amount,
      transactionId: data.transactionId,
      ...(data.usageDate && { usageDate: data.usageDate.getTime() }), // Send as milliseconds
      ...(data.properties && { properties: data.properties }),
    };

    const result = await flowglad(data.customerExternalId).createUsageEvent(usageEventPayload);

    console.log('Usage event created successfully:', result.usageEvent.id);
    return result.usageEvent;
  } catch (error) {
    console.error('Failed to create usage event:', error);
    // Handle error appropriately
    throw error;
  }
};

// Example usage:
/*
reportUsage({
  customerExternalId: 'user_xyz789', // Your app's user ID
  subscriptionId: 'sub_abc123',
  priceSlug: 'price_jkl456',
  amount: 10, // e.g., 10 API calls
  transactionId: 'my-unique-transaction-id-12345',
  // properties: { "userId": "user_qwerty" } // If using count_distinct_properties
}).catch(e => console.error(e));
*/

Creating Usage Events with a Usage Meter

You can also create usage events by referencing the usage meter directly, without requiring a price. This is useful for tracking usage without billing:
import { FlowgladServer } from '@flowglad/server'; // Adjust import based on your setup

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

export const reportUsage = async (data: {
  customerExternalId: string; // The customer ID from YOUR app's database, NOT Flowglad's customer ID
  subscriptionId: string;   // The ID of the usage subscription
  usageMeterSlug: string;    // The slug of the usage meter
  amount: number;           // The quantity of usage (for 'sum' aggregation)
  transactionId: string;    // A unique ID from your system to ensure idempotency
  usageDate?: Date;         // Optional: Defaults to now. Date usage occurred.
  properties?: Record<string, any>; // Required for 'count_distinct_properties' meters
                                   // e.g., { "userId": "user_123" }
}) => {
  try {
    const usageEventPayload = {
      subscriptionId: data.subscriptionId,
      usageMeterSlug: data.usageMeterSlug,
      amount: data.amount,
      transactionId: data.transactionId,
      ...(data.usageDate && { usageDate: data.usageDate.getTime() }), // Send as milliseconds
      ...(data.properties && { properties: data.properties }),
    };

    const result = await flowglad(data.customerExternalId).createUsageEvent(usageEventPayload);

    console.log('Usage event created successfully:', result.usageEvent.id);
    return result.usageEvent;
  } catch (error) {
    console.error('Failed to create usage event:', error);
    // Handle error appropriately
    throw error;
  }
};

// Example usage:
/*
reportUsage({
  customerExternalId: 'user_xyz789', // Your app's user ID
  subscriptionId: 'sub_abc123',
  usageMeterSlug: 'api_calls',
  amount: 10, // e.g., 10 API calls
  transactionId: 'my-unique-transaction-id-12345',
  // properties: { "userId": "user_qwerty" } // If using count_distinct_properties
}).catch(e => console.error(e));
*/
Key parameters for createUsageEvent:
  • subscriptionId: The ID of their active usage subscription.
  • Identifier (exactly one required):
    • priceSlug: The slug of the specific usage price associated with this event (for tracking usage with billing).
    • usageMeterSlug: The slug of the usage meter (for tracking usage without billing).
  • amount: For sum aggregation, this is the quantity of usage (e.g., number of API calls, megabytes transferred). For count_distinct_properties, this is often 1, as the uniqueness is determined by the properties.
  • transactionId: Crucial for idempotency. This should be a unique ID generated by your system for each usage event. If Flowglad receives a createUsageEvent call with a transactionId it has already processed for that usageMeterId, it will not create a duplicate event.
  • usageDate (optional): Timestamp (in milliseconds since epoch) of when the usage occurred. Defaults to the time of the API call. If usage occurs outside the current billing period, it will still be attached to the current open billing period for that subscription.
  • properties (optional): A JSON object. Required if the linked Usage Meter has an Aggregation Type of count_distinct_properties. This object should contain the property you want to count distinct values of (e.g., { "userId": "some_unique_user_id" }).
By following these steps, you can effectively model, track, and bill for various types of usage with Flowglad. Remember that usage events roll up and are used to calculate charges at the end of each billing period.

Client-Side Usage Tracking

In addition to server-side usage event creation, you can also create usage events directly from the client using the useBilling() hook from @flowglad/react. This is useful for real-time tracking where you want immediate feedback in the UI.

When to Use Client-Side vs Server-Side

ApproachBest For
Client-Side (useBilling().createUsageEvent)Real-time UI feedback, simple tracking (clicks, page views), single events per user action
Server-Side (FlowgladServer.createUsageEvent)High-frequency events, sensitive billing logic, bulk recording, full parameter control

Client-Side Example

import { useBilling } from '@flowglad/react'
import { useState } from 'react'

function TokenCounter() {
  const { createUsageEvent } = useBilling()
  const [prompt, setPrompt] = useState('')

  const handleGenerateText = async () => {
    const response = await generateAIText(prompt)

    // Record the tokens consumed
    const result = await createUsageEvent({
      usageMeterSlug: 'ai_tokens',
      amount: response.tokensUsed,
    })
    
    if ('error' in result) {
      console.error('Failed to record usage:', result.error)
    }
  }

  return (
    <div>
      <input 
        value={prompt} 
        onChange={(e) => setPrompt(e.target.value)} 
        placeholder="Enter your prompt"
      />
      <button onClick={handleGenerateText}>Generate</button>
    </div>
  )
}

Smart Defaults

The client-side createUsageEvent provides convenient defaults to simplify common use cases:
  • amount: Defaults to 1 if not provided
  • subscriptionId: Auto-inferred from the customer’s current subscription
  • transactionId: Auto-generated for idempotency if not provided
This means for simple tracking, you only need to specify what you’re tracking:
// Track a single API call
await createUsageEvent({ priceSlug: 'api_calls' })

// Track with custom amount
await createUsageEvent({ usageMeterSlug: 'tokens', amount: 150 })
Client-side usage events do not automatically refresh billing data to avoid performance issues with high-frequency events. Call reload() from useBilling() manually if you need to update the displayed usage balance after recording usage.
For more details on the client-side API, see the React SDK documentation.