npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chatarmin/os

v1.5.1

Published

Type-safe SDK for ChatarminOS - Customer & Subscription Management

Readme

@chatarmin/os

Type-safe SDK for ChatarminOS — the all-in-one platform for B2B SaaS to manage customers, subscriptions, feature access, and billing.

npm version TypeScript

Features

  • 🏢 Company Management — Create, link, and manage customer companies
  • 🎫 Subscription Tiers — Define tiers with features and Stripe pricing
  • Feature Access — Check entitlements and enforce usage limits
  • 📊 Usage Tracking — Metered billing with idempotency support
  • 💳 Stripe Integration — Claim checkout sessions, link subscriptions
  • 🔗 Smart Linking — Intelligent company matching by domain/name/email
  • 👥 Contact Sync — Bulk upsert contacts for each company
  • 🚀 Unified Onboarding — Complete setup in a single API call

Table of Contents


Installation

pnpm add @chatarmin/os
# or
npm install @chatarmin/os
# or
yarn add @chatarmin/os

Quick Start

import { ChatarminOS } from "@chatarmin/os"

const os = new ChatarminOS({
  apiKey: process.env.OS_API_KEY!,
  // Optional: custom base URL for self-hosted
  // baseUrl: 'https://your-os.example.com/api/v1'
})

// Onboard a new customer (single call does everything!)
const result = await os.onboard({
  externalOrgId: "org_abc123", // Your product's org ID
  label: "My Product", // Display label for the product link (required)
  hints: {
    companyName: "Acme Inc",
    domain: "acme.com",
  },
  tierCode: "free",
  contactEmail: "[email protected]",
  contactName: "John Doe",
})

console.log(result.companyId) // Use this for all future API calls
console.log(result.linkStatus) // 'created' | 'linked' | 'already_linked'

API Reference

Companies

Manage customer companies and their links to your product.

companies.getByProductLink(input)

Look up a company by your external organization ID.

const company = await os.companies.getByProductLink({
  externalOrgId: "org_abc123",
})

if (company) {
  console.log(`Found: ${company.name} (${company.id})`)
} else {
  console.log("Company not linked yet")
}

companies.create(input)

Create a new company and link it to your product.

const company = await os.companies.create({
  name: "Acme Inc",
  domain: "acme.com",
  externalOrgId: "org_abc123",
  label: "My Product", // Display label for the product link
  contactEmail: "[email protected]",
  contactName: "John Doe",
  createdAt: "2024-01-15T10:30:00.000Z", // Optional: historical date
})

console.log(company.id) // UUID
console.log(company.shortId) // e.g., "acme-inc"

companies.update(input)

Update company metadata (e.g., backfill historical dates).

await os.companies.update({
  companyId: "uuid-here",
  createdAt: "2023-06-01T00:00:00.000Z",
})

companies.smartLink(input)

Intelligently find and link a company using hints.

const result = await os.companies.smartLink({
  externalOrgId: "org_abc123",
  label: "My Product", // Display label for the product link (required)
  hints: {
    companyName: "Acme Inc",
    domain: "acme.com",
    emails: ["[email protected]", "[email protected]"],
  },
  minConfidence: 0.7, // Default: 0.8
})

switch (result.status) {
  case "already_linked":
    console.log("Already linked to your product")
    break
  case "linked":
    console.log(
      `Auto-linked to ${result.customerName} (${result.confidence}% confidence)`
    )
    break
  case "suggestions":
    console.log("Multiple matches found:", result.suggestions)
    break
  case "no_match":
    console.log("No matching company found")
    break
}

Matching priority:

  1. Domain match → 95% confidence
  2. Name match → up to 80% confidence
  3. Email domain match → 70% confidence

Contacts

Manage people associated with companies.

contacts.create(input)

Create or update a single contact.

const contact = await os.contacts.create({
  companyId: "comp_xxx",
  email: "[email protected]",
  name: "John Doe",
  role: "CEO",
  isPrimary: true,
  avatarUrl: "https://example.com/avatar.jpg",
  metadata: { slackId: "U123" },
})

if (contact.isNew) {
  console.log("Created new contact")
} else {
  console.log("Updated existing contact")
}

contacts.bulkUpsert(input)

Bulk create or update multiple contacts. Recommended for onboarding.

const result = await os.contacts.bulkUpsert({
  companyId: "comp_xxx",
  contacts: [
    { email: "[email protected]", name: "Alice", role: "CEO", isPrimary: true },
    { email: "[email protected]", name: "Bob", role: "CTO" },
    { email: "[email protected]", name: "Charlie", role: "Engineer" },
  ],
})

console.log(`Created: ${result.created}, Updated: ${result.updated}`)
// result.contacts contains individual results with IDs

contacts.list(companyId, primaryOnly?)

List contacts for a company.

// Get all contacts
const contacts = await os.contacts.list("comp_xxx")

// Get only the primary contact
const [primary] = await os.contacts.list("comp_xxx", true)

Features

Check and manage feature access for companies.

features.check(input)

Check if a company has access to a specific feature.

const access = await os.features.check({
  companyId: "comp_xxx",
  featureCode: "ai_credit",
})

console.log({
  enabled: access.isEnabled, // Feature is turned on
  canUse: access.canUse, // Can use right now (not at limit)
  hasQuantity: access.hasQuantity, // Is a quantity-based feature
  usage: access.currentUsage, // Current usage count
  limit: access.quantityLimit, // Max allowed (null = unlimited)
  included: access.includedQuantity, // Free tier before billing
  remaining: access.remaining, // How many left (null = unlimited)
})

if (!access.canUse) {
  throw new Error("Upgrade required")
}

features.listAccess(companyId)

List all features and their access status for a company.

const features = await os.features.listAccess("comp_xxx")

for (const f of features) {
  console.log(`${f.featureName}: ${f.isEnabled ? "✓" : "✗"}`)
  if (f.quantityLimit) {
    console.log(`  Usage: ${f.currentUsage} / ${f.quantityLimit}`)
  }
}

features.setAccess(input)

Update feature access with partial config merge.

// Update by company ID
await os.features.setAccess({
  companyId: "comp_xxx",
  featureCode: "ai_credit",
  isEnabled: true,
  quantityLimit: 1000,
  includedQuantity: 100,
  config: {
    model: "gpt-4",
    maxTokens: 4096,
  },
  source: "manual", // 'subscription' | 'manual' | 'trial' | 'api'
  validUntil: new Date("2025-12-31"), // null for no expiration
})

// Update by external org ID
await os.features.setAccess({
  externalOrgId: "org_abc123",
  featureCode: "team_seats",
  config: { maxSeats: 50 }, // Only updates maxSeats, preserves other config
})

features.getAccessByExternalOrgId(externalOrgId)

Get all features using your product's external org ID.

const result = await os.features.getAccessByExternalOrgId("org_abc123")

console.log(`Company: ${result.companyId}`)
for (const f of result.features) {
  console.log(`${f.featureCode}: ${f.isEnabled}`)
  console.log("  Config:", f.configValues)
}

features.checkByExternalOrgId(externalOrgId, featureCode)

Check a specific feature using your external org ID.

const access = await os.features.checkByExternalOrgId("org_abc123", "ai_credit")

if (access.canUse) {
  console.log(`Remaining: ${access.remaining}`)
}

Billing

Track usage, claim subscriptions, and manage billing.

billing.trackUsage(input)

Track usage for a metered feature.

const result = await os.billing.trackUsage({
  companyId: "comp_xxx",
  featureCode: "ai_credit",
  quantity: 5,
  idempotencyKey: `request_${requestId}`, // Prevents double-counting
  metadata: { model: "gpt-4", tokens: 1500 },
})

console.log({
  currentUsage: result.currentUsage,
  remaining: result.remaining,
  billable: result.billableQuantity, // Amount beyond included tier
  isAtLimit: result.isAtLimit,
})

billing.claimCheckout(input)

Claim a subscription from a completed Stripe Checkout Session.

// In your Stripe checkout success handler
const result = await os.billing.claimCheckout({
  companyId: "comp_xxx",
  checkoutSessionId: "cs_test_xxx", // From Stripe callback
})

if (result.alreadyClaimed) {
  console.log("Subscription was already claimed")
} else {
  console.log(`Claimed subscription: ${result.subscriptionId}`)
}

billing.linkSubscription(input)

Link an existing Stripe subscription to a company.

// When you create subscriptions on YOUR Stripe account
const result = await os.billing.linkSubscription({
  companyId: "comp_xxx",
  stripeSubscriptionId: "sub_xxx",
  stripeCustomerId: "cus_xxx", // Optional: fetched from subscription if omitted
  tierCode: "pro", // Apply tier features
  displayName: "Pro Plan",
})

console.log({
  subscriptionId: result.subscriptionId,
  isNew: !result.alreadyLinked,
  featuresApplied: result.featuresApplied,
})

billing.getStatus(companyId)

Get billing status overview for a company.

const status = await os.billing.getStatus("comp_xxx")

console.log({
  hasBilling: status.hasBillingProfile,
  subscriptions: status.activeSubscriptions.length,
  features: status.enabledFeaturesCount,
})

// Check active tier
if (status.activeSubscriptions[0]?.tier) {
  console.log(`Current tier: ${status.activeSubscriptions[0].tier.name}`)
}

Subscriptions & Tiers

Manage subscription tiers and apply features.

tiers.list()

List all available tiers for your product.

const tiers = await os.tiers.list()

for (const tier of tiers) {
  console.log(`${tier.name} (${tier.code})`)
}
// ['Free', 'Pro', 'Enterprise']

tiers.get(tierCode)

Get detailed tier information including Stripe prices.

const tier = await os.tiers.get("pro")

// Check base fee
if (tier.baseFee) {
  console.log(`Base fee: ${tier.baseFee.stripe.unitAmount / 100}€/mo`)
  console.log(`Price ID: ${tier.baseFee.stripe.priceId}`)
}

// Access features
for (const feature of tier.features) {
  console.log(`${feature.code}:`, feature.configValues)
}

// Get all Stripe price IDs (base fee + feature prices)
console.log("Stripe prices:", tier.stripePriceIds)
// ['price_base', 'price_feature1', 'price_feature2']

tiers.apply(tierCode, options)

Apply a tier's features to a company (without Stripe).

// Apply free tier
await os.tiers.apply("free", {
  companyId: "comp_xxx",
})

// Apply with custom limits
await os.tiers.apply("trial", {
  companyId: "comp_xxx",
  features: {
    ai_credit: { included_quantity: 100 },
    seats: { max_quantity: 10 },
  },
})

subscriptions.create(tierCode, options)

Alias for tiers.apply() — apply a subscription tier.

await os.subscriptions.create("pro", {
  companyId: "comp_xxx",
  features: {
    ai_credit: { included_quantity: 500 },
  },
})

Links

Manually manage product links.

links.create(input)

Create a manual link between your external org ID and an existing company.

await os.links.create({
  companyId: "comp_xxx",
  externalOrgId: "org_abc123",
  label: "Store Vienna", // Optional: display label
  externalUserId: "user_xyz", // Optional: user who created the link
})

links.reset(options?)

Delete all product links for your product. Use before re-importing.

// Basic reset (links only)
const result = await os.links.reset()
console.log(`Deleted ${result.linksDeleted} links`)

// Full reset (links + contacts + MRR)
const result = await os.links.reset({
  deleteContacts: true,
  resetMrr: true,
})
console.log(
  `Deleted ${result.linksDeleted} links, ${result.contactsDeleted} contacts`
)

Onboarding

Complete customer onboarding in a single API call.

The onboard() method handles:

  1. Smart company matching/creation
  2. Product linking
  3. Subscription claiming/linking
  4. Tier feature application

Basic Usage

const result = await os.onboard({
  externalOrgId: "org_abc123", // Your product's org ID (required)
  label: "My Product", // Display label for the product link (required)
  hints: {
    companyName: "Acme Inc",
    domain: "acme.com",
    emails: ["[email protected]"],
  },
  tierCode: "free",
  contactEmail: "[email protected]",
  contactName: "John Doe",
  createdAt: "2024-01-15T10:30:00.000Z", // Optional: historical date
})

console.log({
  companyId: result.companyId,
  companyName: result.companyName,
  linkStatus: result.linkStatus, // 'created' | 'linked' | 'already_linked'
  tierApplied: result.billingStatus?.tierApplied,
})

Scenario 1: User Completed Stripe Checkout

const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  hints: { companyName: "Acme Inc", domain: "acme.com" },
  checkoutSessionId: "cs_test_xxx", // From Stripe checkout callback
})

// result.billingStatus.claimed = true
// result.billingStatus.subscriptionId = 'sub_xxx'

Scenario 2: Free Tier Signup

const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  hints: { companyName: "Acme Inc" },
  tierCode: "free",
  contactEmail: "[email protected]",
})

// result.billingStatus.tierApplied = true

Scenario 3: You Create Stripe Subscription

// 1. Get tier prices
const tier = await os.tiers.get("pro")

// 2. Create subscription on YOUR Stripe account
const stripeSub = await stripe.subscriptions.create({
  customer: stripeCustomerId,
  items: tier.stripePriceIds.map((price) => ({ price })),
})

// 3. Onboard with the subscription
const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  hints: { companyName: "Acme Inc" },
  stripeSubscriptionId: stripeSub.id,
  stripeCustomerId: stripeCustomerId,
  tierCode: "pro",
})

// result.billingStatus.linked = true
// result.billingStatus.tierApplied = true

Handling Existing Customers

const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  hints: { companyName: "Acme Inc" },
})

switch (result.linkStatus) {
  case "already_linked":
    console.log("Welcome back!")
    break
  case "linked":
    console.log("Found existing company, linked!")
    break
  case "created":
    console.log("New company created!")
    break
}

Common Patterns

Feature Gating

async function checkFeatureAccess(orgId: string, feature: string) {
  const access = await os.features.checkByExternalOrgId(orgId, feature)

  if (!access.isEnabled) {
    throw new Error(`Feature ${feature} is not available on your plan`)
  }

  if (!access.canUse) {
    throw new Error(`Usage limit reached for ${feature}. Please upgrade.`)
  }

  return access
}

// Usage
await checkFeatureAccess("org_abc123", "ai_credit")
await performAIOperation()
await os.billing.trackUsage({
  companyId: company.id,
  featureCode: "ai_credit",
  quantity: 1,
})

Stripe Subscription Flow

// 1. User selects a plan → Get tier prices
const tier = await os.tiers.get("pro")

// 2. Create Stripe Checkout Session with tier prices
const session = await stripe.checkout.sessions.create({
  customer: customerId,
  line_items: tier.stripePriceIds.map((price) => ({
    price,
    quantity: 1,
  })),
  success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${baseUrl}/cancel`,
})

// 3. After checkout completes → Claim subscription
const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  checkoutSessionId: session.id,
})

Backfilling Historical Data

import { ChatarminOS } from "@chatarmin/os"
import historicalData from "./migration-data.json"

const os = new ChatarminOS({ apiKey: process.env.OS_API_KEY! })

for (const org of historicalData) {
  // Create company with historical date
  const result = await os.onboard({
    externalOrgId: org.id,
    label: "Imported", // Display label for historical import
    hints: {
      companyName: org.name,
      domain: org.domain,
    },
    tierCode: org.plan,
    contactEmail: org.adminEmail,
    createdAt: org.createdAt, // Historical timestamp
  })

  // Sync contacts
  await os.contacts.bulkUpsert({
    companyId: result.companyId,
    contacts: org.users.map((u) => ({
      email: u.email,
      name: u.name,
      role: u.role,
    })),
  })
}

TypeScript Support

The SDK is fully typed with comprehensive TypeScript definitions.

Importing Types

import { ChatarminOS } from "@chatarmin/os"
import type {
  ChatarminOSConfig,
  CreateCompanyInput,
  SmartLinkInput,
  SmartLinkResult,
  ContactInput,
  FeatureCheckInput,
  FeatureSetAccessInput,
  TrackUsageInput,
  OnboardInput,
  OnboardResult,
  ApplyTierInput,
  ClaimCheckoutInput,
  LinkSubscriptionInput,
} from "@chatarmin/os"

Router Types

import type { AppRouter } from "@chatarmin/os"

Configuration

| Option | Type | Required | Default | Description | | --------- | -------- | -------- | --------------------------------- | --------------------------- | | apiKey | string | ✅ | — | API key from OS admin panel | | baseUrl | string | — | https://os.chatarmin.com/api/v1 | API endpoint |

const os = new ChatarminOS({
  apiKey: process.env.OS_API_KEY!,
  baseUrl: "https://os.chatarmin.com/api/v1", // Default
})

// Local development
const osLocal = new ChatarminOS({
  apiKey: process.env.OS_API_KEY!,
  baseUrl: "http://localhost:3001/api/v1",
})

Getting Your API Key

  1. Go to ChatarminOS → SettingsDevelopersAPI Keys
  2. Click "Create API Key"
  3. Copy the key (format: os_sk_xxxxxxxxxxxx)
  4. Store in environment variables

Error Handling

The SDK uses tRPC under the hood. Errors include structured information:

try {
  await os.billing.trackUsage({
    companyId: "comp_xxx",
    featureCode: "ai_credit",
    quantity: 1000,
  })
} catch (error) {
  if (error instanceof TRPCClientError) {
    console.error("Code:", error.data?.code) // e.g., 'FORBIDDEN'
    console.error("Message:", error.message) // Human-readable message
    console.error("HTTP Status:", error.data?.httpStatus)
  }
}

Common Error Codes

| Code | Description | | --------------------- | -------------------------- | | UNAUTHORIZED | Invalid or missing API key | | FORBIDDEN | No access to this resource | | NOT_FOUND | Company/feature not found | | BAD_REQUEST | Invalid input parameters | | PRECONDITION_FAILED | Usage limit exceeded |


Related Documentation


Support


License

MIT © Chatarmin GmbH