Skip to main content

Customers

Any entity that consumes entitlements.

A customer is any entity that consumes entitlements — a user, an organization, a workspace, a seat. Customers carry their own meters, grants, and overrides. They are the runtime state that Limitr enforces against.


Schema

The Customer type is managed by the SDK. You don't write customers into your policy document directly — you create and modify them through the API.

{
id: string, // Primary ID. Must be unique per policy.
plan: string, // Plan ID this customer is on.
type: string, // Customer type: 'user', 'org', etc. Default: 'user'.
label: string, // Human-facing label. Default: 'User'.
alt_ids: string[], // Alternate IDs (e.g. Stripe customer ID, API key).
refs: string[], // References to other customer IDs (e.g. org ID for a user).
meters: {}, // Per-entitlement consumption state. Managed automatically.
overrides: {}, // Per-entitlement limit overrides. See Entitlements.
grants: {}, // Credit grants. See Topups & Grants.
metadata: {}, // Optional. Arbitrary key-value data.
}

Creating customers

policy.createCustomer()

Creates a new customer and adds them to the policy. All arguments after id are optional.

// Minimal
await policy.createCustomer('user_abc');

// On a specific plan
await policy.createCustomer('user_abc', 'growth');

// Org customer with type and label
await policy.createCustomer('org_xyz', 'enterprise', 'org', 'Acme Corp');

// User with a ref to their org
await policy.createCustomer('user_abc', 'growth', 'user', 'Alice', ['org_xyz']);

Fires a customer-set event. If a Cloud connection is active, the customer is registered with Cloud.

policy.ensureCustomer()

Creates the customer only if they don't already exist. Returns true if a new customer was created, false if they already existed. Prefer this over createCustomer() in cases where the customer may or may not exist.

await policy.ensureCustomer('user_abc', 'starter');

Reading customer state

policy.customer()

Returns the full customer object — plan, meters, grants, overrides, and metadata. Use this to drive usage meters, plan badges, and upgrade prompts in your UI.

const customer = await policy.customer('user_abc');
// {
// id: 'user_abc',
// plan: 'growth',
// type: 'user',
// meters: {
// chat_input: { credit: 'sonnet_input', value: 245000, started: 1718000000000 }
// },
// grants: {
// 'lgrnt_abc123': { credit: 'ai_credit', value: 7.3, starting_value: 10, ... }
// },
// overrides: {},
// metadata: null
// }

policy.customers()

Returns all customers as a single record. Useful for persistence — this is the complete customer state snapshot.

const all = await policy.customers();

policy.customerMetadata()

Returns only the metadata object for a customer.

const meta = await policy.customerMetadata('user_abc');

Modifying customers

policy.setCustomerPlan()

Changes a customer's plan. When overwrite_meters is true (default), resets all meters. Fires customer-set and customer-plan-changed events.

await policy.setCustomerPlan('user_abc', 'enterprise');

policy.setCustomer()

Sets the entire customer object at once. The preferred way to apply multiple changes in a single operation.

await policy.setCustomer(customer); // emits events and updates Cloud

policy.removeCustomer()

Removes a customer from the local policy. Fires customer-removed.

Cloud customers

removeCustomer() does not remove the customer from Limitr Cloud. Use the Cloud dashboard for Cloud customer management.

await policy.removeCustomer('user_abc');

Alternative IDs

Customers can carry multiple IDs — useful for mapping a Stripe customer ID, an API key, or any external identifier to the same Limitr customer. Alternative IDs must be unique per policy.

// Add an alt ID
await policy.addAltID('user_abc', 'cus_stripe_xyz');

// Both resolve to the same customer
await policy.customer('user_abc');
await policy.customer('cus_stripe_xyz');

// Remove an alt ID
await policy.removeAltID('cus_stripe_xyz');

All enforcement methods accept primary IDs or alt IDs interchangeably.

policy.addAltID()

Adds an alternative ID to an existing customer. When event is true (default), fires a customer-set event.

policy.removeAltID()

Removes an alternative ID. The primary ID and all other alt IDs remain valid.


Customer references

The refs field is a list of other customer IDs. References enable org-scoped entitlements: when a user references an org, entitlements with scope: org resolve against the org's meters rather than the user's.

// Create org
await policy.createCustomer('org_xyz', 'enterprise', 'org', 'Acme Corp');

// Create user with a ref to the org
await policy.createCustomer('user_abc', 'growth', 'user', 'Alice', ['org_xyz']);

// Enforcement on a scope:org entitlement draws from org_xyz's meter
await policy.increment('user_abc', 'seats'); // → org_xyz's seat pool

policy.customerRefs()

Returns the list of referenced customer IDs.

const refs = await policy.customerRefs('user_abc'); // ['org_xyz']

Metadata

Arbitrary key-value data attached to a customer. Useful for storing external system IDs, feature flags, or any state you want accessible at enforcement time.

Capture email early

Metadata is important for customer segments, price modifications like coupons, and billing workflows in Limitr Cloud. At minimum, capture email if you plan to use the customer object for billing — it's much easier to add it at creation time than to backfill later.

await policy.createCustomer('user_abc', 'starter', 'user', 'Alice', null, null, {
stripe_id: 'cus_xyz',
account: 'example',
email: 'user@example.com',
internal_tier: 'pilot',
});

const meta = await policy.customerMetadata('user_abc');
// { stripe_id: 'cus_xyz', account: 'example', email: 'user@example.com', internal_tier: 'pilot' }

Subscription billing

ensureCustomerPlanQuantity() increments the plan's subscription entitlement if the customer's meter is below 1. Call this once per billing period or at plan activation to trigger the subscription charge event.

await policy.ensureCustomerPlanQuantity('user_abc');

Requires a subscription entitlement on the plan — typically a soft-limit entitlement with value: 0 so the first increment fires a meter-overage event that your billing code handles. See Plans → subscription for setup.

Does nothing until the trial period has elapsed, if trial_period is set on the plan.