Seat Based Billing Models

In addition to usage-based billing, Schematic enables you to implement seat-based billing models, with the ability to:

  • Include a base number of seats in the plan
  • Override the base number of seats for a specific company
  • Allow customers to purchase additional seats at a per-seat price

Pricing models for Seat Based Billing

The 2 most common pricing models for seat-based billing are Pay in advance and Overage.

Pay in advance

Traditionally, pay in advance models have been the most common pricing model for seat-based billing. In pay in advance models, customers purchase a number of seats up front, and then can use them as needed. If a customer has hit their limit and requires more seats, they must complete a checkout flow to purchase additional seats.

Overage

Recently, overage models have become more common for seat-based billing. In overage models, customers are charged a per-seat price for each seat they use beyond the base number of seats included in the plan. Instead of requiring a checkout flow to purchase additional seats, customers simply use as many seats as they need, and are charged accordingly at the end of the billing period. The lower friction to add seats has made this popular for products like Figma.

Implementing Seat Based Billing

Seat-based billing in Schematic is implemented using trait-based entitlements. A trait tracks the current number of seats in use for each company, and Schematic compares that value against the entitlement limit to determine whether to enable or disable the corresponding feature flag.

Setting up the entitlement

  1. Create a feature and choose “Trait-based” in the control dropdown.
  2. Follow the wizard to specify the trait key that will represent seat usage (e.g. seats_used).
  3. Entitle the feature to a plan and set the limit. You have a few options:
    • Numerical limit — every company on the plan gets the same seat limit.
    • No limit — unlimited seats, useful for enterprise or internal plans.
    • Trait — each company’s limit is read from a trait on their profile (e.g. seats_allocated), which is useful when seat counts are negotiated per customer.
Under most common situations, you’ll want to choose Numerical limit (e.g. “Pro plan grants 5 seats”) or No limit (e.g. “Pro plan grants unilimited seats”).

Reporting seat usage

To let Schematic know how many seats a company is currently using, upsert the trait value on the company profile whenever a seat is added or removed:

1import { SchematicClient } from "@schematichq/schematic-typescript-node";
2
3const client = new SchematicClient({ apiKey: process.env.SCHEMATIC_API_KEY });
4
5// Called when a user is added or removed — update the current seat count
6await client.companies.upsertCompany({
7 keys: { "your-company-key": "value" },
8 traits: { seats_used: 5 },
9});
1from schematic import Schematic
2
3client = Schematic(api_key="your-api-key")
4
5# Called when a user is added or removed — update the current seat count
6client.companies.upsert_company(
7 keys={"your-company-key": "value"},
8 traits={"seats_used": 5},
9)

You don’t have to report seat usage to Schematic to use entitlements. If you manage seat counts in your own system, you can check the entitlement limit directly and enforce access without sending usage to Schematic. However, reporting usage to Schematic enables usage visibility in the Schematic UI and powers usage reporting features.

Checking the entitlement in your application

Checking whether a company has available seats works the same as any other feature flag check. Schematic evaluates the current trait value against the entitlement limit automatically. The flag returns true when seat usage is below the limit and false when usage meets or exceeds it.

1import { SchematicClient } from "@schematichq/schematic-typescript-node";
2
3const client = new SchematicClient({ apiKey: process.env.SCHEMATIC_API_KEY });
4
5const evaluationCtx = {
6 company: { id: "your-company-id" },
7 user: { userId: "your-user-id" },
8};
9
10client
11 .checkFlagWithEntitlement(evaluationCtx, "your-seats-feature-flag")
12 .then((resp) => {
13 console.log(`Seat available: ${resp.value}`); // false when at or above limit
14
15 if (resp.entitlement) {
16 console.log(`Entitlement type: ${resp.entitlement.valueType}`);
17 console.log(`Usage: ${resp.entitlement.usage}`);
18 }
19 })
20 .catch(console.error);
21
22client.close();

Supporting multiple seat types

Because seat types are modeled as individual trait-based features, you can support multiple seat types within the same plan. For example, a plan could have separate entitlements for editor_seats and viewer_seats, each with its own limit and usage trait. Each seat type gets its own feature flag, and you report usage separately for each trait.

Overrides

Overrides work on seat-based entitlements. If a specific company needs a different seat limit than their plan provides (for example, a customer negotiated extra seats mid-cycle), you can set a company-level override without changing the plan.