Owostack
SDK Reference

Catalog Builders

Reference: metered(), boolean(), creditSystem(), plan() — define features and plans as code

Catalog Builders

Builder functions for defining features and plans declaratively. Features become handles you can use directly for .check() and .track().

metered(slug, opts?)

Create a metered feature handle. Metered features have numeric limits that reset on a schedule.

import { metered } from "@owostack/core";

const apiCalls = metered("api-calls", { name: "API Calls" });

Parameters

ParameterTypeRequiredDescription
slugstringYesUnique feature identifier
opts.namestringNoHuman-readable name (auto-generated from slug if omitted)

Methods

.limit(value, config?)

Create a plan feature entry with a specific limit.

apiCalls.limit(1000);
apiCalls.limit(50000, { reset: "daily" });
apiCalls.limit(50000, {
  overage: "charge",
  overagePrice: 100,
  maxOverageUnits: 100000,
});
ParameterTypeDefaultDescription
valuenumberUsage limit per period
config.resetResetInterval"monthly"Reset schedule
config.overage"block" | "charge""block"What happens when limit is exceeded
config.overagePricenumberPrice per overage unit (minor currency)
config.maxOverageUnitsnumberHard cap on overage units per period
config.billingUnitsnumber1Package size for billing
config.creditCostnumberCost in credits per unit

.unlimited()

Create a plan feature entry with no limit.

apiCalls.unlimited();

.config(opts)

Create a plan feature entry with full config object.

apiCalls.config({
  limit: 50000,
  reset: "monthly",
  overage: "charge",
  overagePrice: 100,
});

.check(customer, opts?)

Check if a customer has access to this feature.

const result = await apiCalls.check("user_123");
const result = await apiCalls.check("user_123", { value: 5 });
const result = await apiCalls.check("user_123", { sendEvent: true });

Returns Promise<CheckResult>.

.track(customer, value?, opts?)

Track usage for this feature.

await apiCalls.track("user_123");
await apiCalls.track("user_123", 5);
await apiCalls.track("user_123", 1, { entity: "workspace_123" });

Returns Promise<TrackResult>.


boolean(slug, opts?)

Create a boolean feature handle. Boolean features are either enabled or disabled per plan — no usage tracking.

import { boolean } from "@owostack/core";

const analytics = boolean("analytics", { name: "Analytics Dashboard" });

Parameters

Same as metered().

Methods

.on()

Feature is included in this plan.

analytics.on();

.off()

Feature is NOT included in this plan.

analytics.off();

.check(customer, opts?)

Check if a customer has access to this feature.

const { allowed } = await analytics.check("user_123");

Returns Promise<CheckResult>.

Boolean features have no .track() method — the type system enforces this.


creditSystem(slug, config)

Create a credit system definition. A credit system abstracts usage across multiple features into a single "credit" balance.

import { creditSystem, metered } from "@owostack/core";

const gpt4 = metered("gpt-4");
const dallE = metered("dall-e");

const aiCredits = creditSystem("ai-credits", {
  name: "AI Credits",
  features: [
    gpt4(20), // GPT-4 costs 20 credits per track()
    dallE(50), // Dall-E costs 50 credits per track()
  ],
});

Parameters

ParameterTypeRequiredDescription
slugstringYesUnique credit system identifier
config.namestringNoHuman-readable name
config.descriptionstringNoDescription
config.featuresFeatureHandle[]YesArray of features that consume from this system

Methods

.credits(amount, config?)

Include a specific amount of credits for this system in a plan.

aiCredits.credits(1000, { reset: "monthly", overage: "charge" });

plan(slug, config)

Create a plan definition for the catalog.

import { plan } from "@owostack/core";

plan("pro", {
  name: "Pro",
  price: 500000,
  currency: "NGN",
  interval: "monthly",
  features: [
    apiCalls.limit(50000, { overage: "charge", overagePrice: 100 }),
    aiCredits.credits(1000),
    analytics.on(),
    seats.limit(20, { reset: "never" }),
  ],
});

Parameters

ParameterTypeRequiredDescription
slugstringYesUnique plan identifier
config.namestringYesHuman-readable plan name
config.pricenumberYesPrice in minor currency units (e.g. kobo)
config.currencyCurrencyYesCurrency code ("NGN", "GHS", "ZAR", "KES", "USD")
config.intervalPlanIntervalYesBilling interval ("monthly", "yearly", etc.)
config.featuresPlanFeatureEntry[]YesArray of feature entries from .limit(), .credits(), etc.
config.descriptionstringNoPlan description
config.planGroupstringNoGroup for upgrade/downgrade logic
config.trialDaysnumberNoTrial period in days
config.metadataRecord<string, unknown>NoCustom metadata

owo.sync()

Push the catalog to the API. Creates and updates features, credit systems, and plans.

const result = await owo.sync();

Returns Promise<SyncResult>

interface SyncResult {
  success: boolean;
  features: { created: string[]; updated: string[]; unchanged: string[] };
  creditSystems: { created: string[]; updated: string[]; unchanged: string[] };
  plans: { created: string[]; updated: string[]; unchanged: string[] };
  warnings: string[];
}

CLI: owo sync

Push a catalog from the command line.

npx owo sync [options]
OptionDescription
--config <path>Path to config file (default: ./owo.config.ts)
--dry-runShow what would change without applying
--key <api-key>API secret key (or set OWOSTACK_SECRET_KEY env var)
--url <api-url>API URL override

Example config file

// owo.config.ts
import { Owostack, metered, boolean, creditSystem, plan } from "@owostack/core";

const apiCalls = metered("api-calls");
const aiCredits = creditSystem("ai-credits", {
  features: [apiCalls(1)],
});

export default new Owostack({
  secretKey: process.env.OWOSTACK_SECRET_KEY!,
  catalog: [
    plan("starter", {
      name: "Starter",
      price: 0,
      currency: "NGN",
      interval: "monthly",
      features: [aiCredits.credits(1000)],
    }),
    plan("pro", {
      name: "Pro",
      price: 500000,
      currency: "NGN",
      interval: "monthly",
      features: [aiCredits.credits(50000)],
    }),
  ],
});

On this page