# @chatarmin/os 中文文档

规范地址：https://npmcn.com/package/%40chatarmin/os/

版本：1\.44\.0
npm 元数据更新时间：2026-11-08T09:41:09.333Z
中文译文更新时间：2026-11-09T11:28:52.422Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40chatarmin/os
原文对照：https://npmcn.com/package/%40chatarmin/os/?lang=original
项目主页：https://github.com/chatarmin-com/os#readme
源码仓库：https://github.com/chatarmin-com/os

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：366 kB，152 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：2 个
- peer 依赖：typescript ^5\.0\.0
- 首次发布：2026-01-08T08:38:40.660Z
- 最新版本发布：2026-11-08T09:41:09.153Z
- 近 30 天下载量：26381（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：62（近 12 个月 62 个）

## 中文简介

ChatarminOS 的 SDK 类型安全 - 客户和订阅管理

## 安装

```sh
npm install @chatarmin/os
```

也可以使用：`pnpm add @chatarmin/os`、`yarn add @chatarmin/os`、`bun add @chatarmin/os`

## README

# @chatarmin/os (中文(简体) )

> Type-security SDK for ChatarminOS——为B2B SaaS管理客户,订阅,特性访问,和计费的全能平台.

[![npm version](https://img.shields.io/npm/v/@chatarmin/os.svg)](https://www.npmjs.com/package/@chatarmin/os) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)

## 特征

-   🏢 **公司管理** - 创建、链接和管理客户公司
-   🎫 **订阅级别** - 界定带有特征和条纹定价的等级
-   ✨ **特性访问** - 检查应享权利并强制执行使用限制
-   📊 **用法跟踪** ——用"一能"支持计算账单
-   💳 **条纹融合** ——报销结账会话,链接订阅
-   🔗 **智能链接** ——智能公司按域名/名/电子邮件进行匹配
-   👥 **联系人同步** ——各公司频繁增加联系人
-   🚀 **统一登入** ——在一个API呼叫中完成设置

* * *

## 目录

-   [安装](https://npmcn.com/package/%40chatarmin/os/#readme-installation)
-   [快速启动](https://npmcn.com/package/%40chatarmin/os/#readme-quick-start)
-   [API 参考](https://npmcn.com/package/%40chatarmin/os/#readme-api-reference)
    -   [公司](https://npmcn.com/package/%40chatarmin/os/#readme-companies)
    -   [联系人](https://npmcn.com/package/%40chatarmin/os/#readme-contacts)
    -   [特征](https://npmcn.com/package/%40chatarmin/os/#readme-features)
    -   [计费](https://npmcn.com/package/%40chatarmin/os/#readme-billing)
    -   [订阅级别( T)](https://npmcn.com/package/%40chatarmin/os/#readme-subscriptions--tiers)
    -   [链接](https://npmcn.com/package/%40chatarmin/os/#readme-links)
    -   [上岗](https://npmcn.com/package/%40chatarmin/os/#readme-onboarding)
    -   [产品 Webhooks](https://npmcn.com/package/%40chatarmin/os/#readme-product-webhooks)
-   [常见模式](https://npmcn.com/package/%40chatarmin/os/#readme-common-patterns)
-   [类型脚本支持](https://npmcn.com/package/%40chatarmin/os/#readme-typescript-support)
-   [配置](https://npmcn.com/package/%40chatarmin/os/#readme-configuration)
-   [处理错误](https://npmcn.com/package/%40chatarmin/os/#readme-error-handling)

* * *

## 安装

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

* * *

## 快速启动

```typescript
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: "admin@acme.com",
  contactName: "John Doe",
})

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

* * *

## API 参考

### 公司

管理客户公司及其与您产品的联系.

#### `companies.get(input)`

找一家由你的外部组织 ID或ChatarminOS公司ID.

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

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

#### `companies.create(input)`

创建一新公司,并与您的产品链接.

```typescript
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: "admin@acme.com",
  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)`

更新公司元数据(如回填历史日期).

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

### 联系人

管理与公司有关的人员.

#### `contacts.create(input)`

创建或更新单个联系人.

```typescript
const contact = await os.contacts.create({
  companyId: "comp_xxx",
  email: "john@acme.com",
  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)`

批量创建或更新多个联系人. **建议入职.**

```typescript
const result = await os.contacts.bulkUpsert({
  companyId: "comp_xxx",
  contacts: [
    { email: "ceo@acme.com", name: "Alice", role: "CEO", isPrimary: true },
    { email: "cto@acme.com", name: "Bob", role: "CTO" },
    { email: "dev@acme.com", name: "Charlie", role: "Engineer" },
  ],
})

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

#### `contacts.list(companyId, primaryOnly?)`

列出公司的联系人 .

```typescript
// 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)
```

* * *

### 特征

检查和管理公司的特性访问.

**标识符 :** 通过 **`featureCode`** 输入(例如. `"ai_credit"`) (中文(简体) ). 答复包括: `featureCode` 财务报告和审定财务报表 `featureAccessId`。代码设置为特性创建,不通过 API 重新命名 `featureName`,或创建新特性并迁移到一个真正的重命名。 见 [`product-billing-api.md`](https://npmcn.com/package/docs/engineering/product-billing-api.md#feature-identifiers-featurecode) 详细情况.

#### `features.check(input)`

请检查access-date=中的日期值 (帮助) 公司能否访问特定功能.

```typescript
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)`

列出公司的所有功能及其接入状态.

```typescript
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)`

更新特性访问方式 **部分配置合并**。 。 。 .

```typescript
// 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)`

使用您的产品外部 Org ID 获取所有特性 .

```typescript
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)`

使用外部 Org ID 检查特定特性 .

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

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

* * *

### 计费

跟踪使用情况、索偿订阅和管理账单.

> **API 参考 :** [`docs/engineering/product-billing-api.md`](https://npmcn.com/package/docs/engineering/product-billing-api.md) - 要求/答复的完整形状 `os.billing.*` 方法.

#### `billing.trackUsage(input)`

用于调制功能的音轨用法 .

```typescript
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)`

要求订阅已完成的Frede取出会话.

```typescript
// 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)`

将现有的Frade订阅链接到公司.

```typescript
// 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(companyIdOrInput)`

公司快速条纹订阅状态—— `activeSubscriptions` (单位:千美元)`active` 编号 : `trialing` 编号 : `past_due`),解决了计费配置,并启用特性计数。 范围为产品链接的开单情况 `externalOrgId` 提供.

见 [产品范围计费概况—— `getStatus` 实例](https://npmcn.com/package/docs/engineering/product-billing-api.md#example-getstatus-for-subscription-health) 用于完整行走+样本反应.

```typescript
const status = await os.billing.getStatus('ee0f4a19-2b69-4969-8807-d0013f1670ee')

const statusByOrg = await os.billing.getStatus({ externalOrgId: 'org_kKZHiUHBSjdu' })

if (status.activeSubscriptions[0]?.status === 'past_due') {
  // gate access for this external org
}

console.log({
  stripeCustomer: status.billingProfile?.stripeCustomerId,
  subscriptionStatus: status.activeSubscriptions[0]?.status,
  features: status.enabledFeaturesCount,
})
```

#### `billing.getOverview(input)`

合并计费页有效载荷:公司、计费概况、主要订阅和最近的发票.

```typescript
const overview = await os.billing.getOverview({
  companyId: "comp_xxx",
  invoiceLimit: 12,
  includeUsage: true, // optional: embed usage rows
})

console.log({
  plan: overview.subscription?.tier?.name,
  status: overview.subscription?.status,
  paymentMethod: overview.billingProfile?.primaryPaymentMethod,
  invoices: overview.invoices.length,
  usageRows: overview.usage?.length,
})
```

#### `companies.list` 编号 : `companies.search`

```typescript
const newest = await os.companies.list({ sort: 'createdAt', limit: 50 })
const matches = await os.companies.search({ query: 'acme', sort: 'createdAt' })
```

`sort` 默认为 `id`。 。 。 . `createdAt` 是最新的第一,光标包括时间戳,所以链接不会跳过行.

#### `companies.update` 编号 : `companies.listLinks`

```typescript
await os.companies.update({
  externalOrgId: 'org_abc123',
  name: 'Acme GmbH',
  domain: 'acme.com',
})

const links = await os.companies.listLinks({ externalOrgId: 'org_abc123' })
```

#### `contacts.update` 编号 : `contacts.unlink`

```typescript
await os.contacts.update({
  companyId: company.id,
  email: 'jane@acme.com',
  role: 'Owner',
})

await os.contacts.unlink({ companyId: company.id, email: 'jane@acme.com' })
```

`unlink` 取消公司的联系人。 只有在没有其他公司继续使用时,个人记录才会被删除.

#### `billing.listClientUsage(input)`

在一个时期内对每个关联客户端的使用. 更喜欢循环 `getUsage` 给管理员看看. `startingOn` 包容性, `endingBefore` 这是独家的,最长366天。 API 键将调用范围限制到其产品; 设置 `includeAllProducts: true` 将每个产品都纳入该组织。 可选 `companyIds` 财务报告和审定财务报表 `externalOrgIds` 缩小结果。 奥米 `featureCode` 以返回所有使用过的特性.

```typescript
const usage = await os.billing.listClientUsage({
  startingOn: new Date('2026-06-01T00:00:00.000Z'),
  endingBefore: new Date('2026-07-01T00:00:00.000Z'),
  includeAllProducts: true,
})

const filtered = await os.billing.listClientUsage({
  startingOn: new Date('2026-06-01T00:00:00.000Z'),
  endingBefore: new Date('2026-07-01T00:00:00.000Z'),
  companyIds: ['f9c9b060-6f83-4b57-a34a-0d84951767cb'],
  externalOrgIds: ['org_FVCNOtEdpeeP'],
  featureCode: 'ai_credit',
})
```

`usage.companies[].links[].features[]` 包含 `usage`, (中文(简体) ), `includedQuantity`, (中文(简体) ), `billableQuantity`,以及 `estimatedOverageCents`津贴是应享权利的数量,不按比例分配给窗口.

#### `billing.listClientRevenue(input)`

工作人员读取:每个客户的发票、付款和退款都用Strepe发票OS镜像所建。 范围为API关键产品组织. 与该产品有联系的客户为: `cx_linked`; 所有其他为 `no_cx_link` 并分别分列.

每个客户每个货币有一个条目。 税前收入净额分为订阅、计算(按 `meterCode`编号 :`featureCode`,比如说. `chatarmin_ai_02`),设置费和一次性金额. `periodBasis` 实值 `invoice_period` 违约(Stripe的发票期,即拖欠账单的使用情况)或 `paid_at`获取页面 `limit` 财务报告和审定财务报表 `cursor`,以及 `totals` 覆盖每一页. `completeness.issues` 解释一下可能缺少什么.

```typescript
const revenue = await os.billing.listClientRevenue({
  startingOn: new Date('2026-03-01T00:00:00.000Z'),
  endingBefore: new Date('2026-04-01T00:00:00.000Z'),
  externalOrgIds: ['org_FVCNOtEdpeeP'],
})

const next = revenue.nextCursor
  ? await os.billing.listClientRevenue({
      startingOn: new Date('2026-03-01T00:00:00.000Z'),
      endingBefore: new Date('2026-04-01T00:00:00.000Z'),
      cursor: revenue.nextCursor,
    })
  : null
```

见 `docs/engineering/product-billing-api.md` 用于行分类、完整性代码和退款回填.

#### `billing.getSalesCommission(input)`

工作人员为:每个账户执行人一个月的佣金,按阅读时计算。 在赢得Pipedrive客户交易时拥有该客户交易的AE在月份支付的发票的许可证行数;在月份贷记或退还的许可证被扣除。 使用费(AI, contacts,Meta),设置费和其他一次性收费从不计数.

```typescript
const october = await os.billing.getSalesCommission({
  month: '2026-10',
  accountExecutives: ['1001', '1002'], // Pipedrive user ids
  dealsWonFrom: '2026-05-01',
  sdrs: ['2001'],
})
// october.accountExecutives[i]: { name, paidMrrCents, deductionMrrCents, netMrrCents, payments, deductions }
```

见 `docs/engineering/product-billing-api.md` 归属和行规则.

#### `billing.getUsage(companyIdOrInput, options?)`

Metronome风格的用法聚合. 回返 `{ data: UsageRecord[] }` ——地貌第一地筑巢,每个地貌计费周期.

**公司范围:** 通过 **`companyId`** 作为第一个字符串参数,或通过输入对象 **`companyId`** 或者说 **`externalOrgId`** (一个要求)。 偏爱 `externalOrgId` 当CX只知道Org swit——使用范围与产品链接.

```typescript
// CX-native (single product link)
const { data } = await os.billing.getUsage({
  externalOrgId: 'org_FVCNOtEdpeeP',
  windowSize: 'none',
})

// Or companyId as first arg
const byCompany = await os.billing.getUsage('comp_xxx', { windowSize: 'none' })
```

-   **`data[].featureCode`** - 稳定的地物弹
-   **`data[].cycles[]`** 这一功能的计费周期(`periodOffset`,范围, `usage[]`(中文(简体) )

`windowSize` 控制是否为 `usage` 分数是时间总和或时间桶. 过滤器为 **`featureCode`** (平稳弹),不是 `featureAccessId` 看到了吗 [特性标识符](https://npmcn.com/package/docs/engineering/product-billing-api.md#feature-identifiers-featurecode)。 。 。 .

**`periodOffsetRange`** (整个计费周期的时间范围):

| 意图 | `periodOffsetRange` |
| --- | --- |
| 当前周期( 默认) | 删除或 `{ from: 0, to: 0 }` |
| 仅上一个 | `{ from: -1, to: -1 }` |
| 当前 + 前一个 | `{ from: -1, to: 0 }` |
| 12个循环拾取器 | `{ from: -11, to: 0 }` |

多周期范围要求 `windowSize: 'none'` (最多12个周期)。 无法结合 `startingOn`编号 :`endingBefore`。 。 。 .

每个 `cycles[]` 桶包括 `subscriptionItem` 财务报告和审定财务报表 `summary` 当它有用行. `usage[]` 保持稀疏(`value` + 日期).

**响应形状 :**

```typescript
interface UsageQueryResult {
  data: UsageRecord[]
}

interface UsageRecord {
  featureCode: string
  featureName: string
  cycles: UsageCycleBucket[]
}

interface UsageCycleBucket {
  periodOffset: number
  startingOn: Date
  endingBefore: Date
  label: string
  subscriptionItem?: UsageSubscriptionItem // present when cycle has usage rows
  summary?: UsageCycleSummary // totals + projection; present when cycle has usage rows
  usage: UsagePoint[] // thin: value + dates (+ optional identity/grouping)
}

interface UsagePoint {
  value: number
  startingOn: Date
  endingBefore: Date
  featureAccessId?: string
  meterCode?: string
  groupKey?: string | null // with groupBy: 'productLink'
  groupValue?: string | null
  productLinkId?: string | null // groupBy: 'productLink', or bucketed multi-link companyId
  productLinkLabel?: string | null
  externalOrgId?: string | null
}
```

读取帐单 `cycle.summary` 财务报告和审定财务报表 `cycle.subscriptionItem` - 不是从 `usage[]` 点.

`productLinkId` (+标签, `externalOrgId`)出现于 `usage[]` 点 `groupBy: 'productLink'`,或装入桶 `companyId` 多个产品链接共享公司时的询问( 无) `groupKey`) (中文(简体) ).

| `windowSize` | `cycles[].usage` | 计费背景 |
| --- | --- | --- |
| `'none'` | 1点 | `subscriptionItem` + 键 `summary` (总是) |
| `'day'` 编号 : `'week'` 编号 : `'month'` | N 细点 | 相同的——每轮开一次帐,而不是每桶开一次帐 |

#### 实例 `windowSize`

**`windowSize: 'none'`** - 总期间:

```json
{
  "data": [{
    "featureCode": "messages",
    "featureName": "Messages",
    "cycles": [{
      "periodOffset": 0,
      "startingOn": "2026-07-01T00:00:00.000Z",
      "endingBefore": "2026-08-01T00:00:00.000Z",
      "label": "Jul 1, 2026 – Aug 1, 2026",
      "subscriptionItem": {
        "includedQuantity": 100,
        "unitAmountCents": 500,
        "currency": "eur"
      },
      "summary": {
        "totalUsage": 120,
        "billableQuantity": 20,
        "estimatedOverageCents": 10000,
        "projectedBillableQuantity": 240,
        "projectedOverageCents": 70000
      },
      "usage": [{
        "value": 120,
        "startingOn": "2026-07-01T00:00:00.000Z",
        "endingBefore": "2026-08-01T00:00:00.000Z"
      }]
    }]
  }]
}
```

**`windowSize: 'day'`** 每日图表桶:

```json
{
  "data": [{
    "featureCode": "messages",
    "featureName": "Messages",
    "cycles": [{
      "periodOffset": 0,
      "subscriptionItem": { "includedQuantity": 100 },
      "summary": { "totalUsage": 20, "billableQuantity": 0 },
      "usage": [
        { "value": 8,  "startingOn": "2026-07-01T00:00:00.000Z", "endingBefore": "2026-07-02T00:00:00.000Z" },
        { "value": 12, "startingOn": "2026-07-02T00:00:00.000Z", "endingBefore": "2026-07-03T00:00:00.000Z" }
      ]
    }]
  }]
}
```

**多周期** (单位:千美元)`periodOffsetRange: { from: -1, to: 0 }`:

```json
{
  "data": [{
    "featureCode": "messages",
    "featureName": "Messages",
    "cycles": [
      { "periodOffset": 0, "label": "Jul 1 – Aug 1", "summary": { "totalUsage": 120, "billableQuantity": 20 }, "usage": [{ "value": 120 }] },
      { "periodOffset": -1, "label": "Jun 1 – Jul 1", "summary": { "totalUsage": 98, "billableQuantity": 0 }, "usage": [{ "value": 98 }] }
    ]
  }]
}
```

全部实例: [`docs/engineering/product-billing-api.md#billinggetusage`](https://npmcn.com/package/docs/engineering/product-billing-api.md#billinggetusage)

```typescript
const { data } = await os.billing.getUsage('comp_xxx', { windowSize: 'none' })
const messages = data.find((r) => r.featureCode === 'messages')
const cycle = messages?.cycles[0]
const currentTotal = cycle?.usage[0]?.value
const overage = cycle?.summary?.billableQuantity
const cost = cycle?.summary?.estimatedOverageCents

const daily = await os.billing.getUsage('comp_xxx', {
  windowSize: 'day',
  featureCode: 'messages',
})
const dailySeries = (daily.data[0]?.cycles[0]?.usage ?? []).map((point) => ({
  day: point.startingOn.toISOString().slice(0, 10),
  usage: point.value,
}))

// Previous billing period totals
const lastMonth = await os.billing.getUsage('comp_xxx', {
  windowSize: 'none',
  periodOffsetRange: { from: -1, to: -1 },
})

// Last 12 billing cycles (cycle picker)
const history = await os.billing.getUsage('comp_xxx', {
  windowSize: 'none',
  periodOffsetRange: { from: -11, to: 0 },
})
// history.data[0].cycles → one bucket per period; cycle.usage[0] → period total

// Custom sub-range within the current billing period (both dates required)
// usage[] points cover the sub-range; summary totals match it; projections use the full cycle
const week = await os.billing.getUsage('comp_xxx', {
  windowSize: 'day',
  featureCode: 'messages',
  startingOn: new Date('2026-07-10T00:00:00Z'),
  endingBefore: new Date('2026-07-17T00:00:00Z'),
})
```

| `windowSize` | 形状 |
| --- | --- |
| `'none'` | 每个特性一分(多个产品链接共享一个公司时的折合总额;使用) `groupBy: 'productLink'` 每行) |
| `'day'` 编号 : `'week'` 编号 : `'month'` | 每桶每地一分;多个产品链接分享公司时每桶每链接一分(`productLinkId` 每个点) |

| 时间范围 | 何时使用 |
| --- | --- |
| 删除 | 当前计费期(违约) |
| `periodOffsetRange: { from: -1, to: -1 }` | 上一个计费期 |
| `periodOffsetRange: { from: -11, to: 0 }` | 过去12个计费周期 |
| `startingOn` + 键 `endingBefore` | 内部的子距离 **当前** 周期(计算;总数按子范围排列;预测使用全周期) |

#### `billing.exportUsage(companyIdOrInput, options?)`

将总使用量导出为 CSV. 接受与 `getUsage` (加上隐含) `format: 'csv'`CSV包括a `periodOffset` 栏(第一栏),用于多周期出口。 文件名使用导出周期界限 : `usage_{windowSize}_{companyId}_{periodStart}_{periodEnd}.csv`。 。 。 .

```typescript
const csv = await os.billing.exportUsage({
  externalOrgId: 'org_FVCNOtEdpeeP',
  windowSize: 'none',
  periodOffsetRange: { from: -11, to: 0 },
})
// csv.filename → "usage_none_<companyId>_2026-06-01_2026-08-01.csv"
// csv.content → first line:
// periodOffset,featureCode,featureName,value,startingOn,endingBefore,groupKey,groupValue,productLinkId,productLinkLabel,externalOrgId,includedQuantity,billableQuantity,quantityLimit,remaining,percentUsed,unitAmountCents,currency,estimatedOverageCents,projectedBillableQuantity,projectedOverageCents
```

#### `billing.listInvoices(companyIdOrInput, options?)`

列出公司发票(不包括汇票/票).

```typescript
const { invoices } = await os.billing.listInvoices("comp_xxx", { limit: 24 })
```

#### `billing.getPaymentMethod(companyIdOrInput)`

已解决的收费情况付款方法摘要.

```typescript
const { billingProfile } = await os.billing.getPaymentMethod("comp_xxx")
```

#### `billing.createPortalSession(input)`

开放Frede客户端 用于管理收费流量. `returnUrl` 必须在允许的产品主机上(`products.metadata.billing.returnUrlHosts`) (中文(简体) ).

```typescript
const { url } = await os.billing.createPortalSession({
  companyId: "comp_xxx",
  returnUrl: "https://app.example.com/settings/billing",
})

// When a company has multiple Stripe customers, target a specific billing profile:
const { url: profileUrl } = await os.billing.createPortalSession({
  companyId: "comp_xxx",
  stripeCustomerId: "cus_xxx",
  returnUrl: "https://app.example.com/settings/billing",
})

// Redirect the user to url
```

#### `billing.resolveInvoicePaymentUrl(input)`

解决特定发票的托管发票付款URL.

```typescript
const { hostedInvoiceUrl } = await os.billing.resolveInvoicePaymentUrl({
  companyId: "comp_xxx",
  invoiceId: "inv_xxx",
})
```

#### `billing.listPastDuePaymentUrls(companyIdOrInput)`

列出过期的发票以及付款地址.

```typescript
const { items } = await os.billing.listPastDuePaymentUrls("comp_xxx")
```

#### `billing.sendPastDueInvoice(input)`

通过 Strape 电子邮件过期发票( 当收集方法为 `send_invoice`) (中文(简体) ).

```typescript
await os.billing.sendPastDueInvoice({
  companyId: "comp_xxx",
  invoiceId: "inv_xxx",
})
```

#### `billing.syncCompanyFromStripe(input)`

调取Frede的帐单、订阅和功能链接.

```typescript
const result = await os.billing.syncCompanyFromStripe({
  companyId: "comp_xxx",
  stripeCustomerId: "cus_xxx",
})

console.log({
  subscriptionsSynced: result.subscriptionsSynced,
  featuresLinked: result.featuresLinked,
})
```

#### `billing.relinkBillingProfile(input)`

将公司开具的开票情况换成新的"条纹"客户(破坏性).

```typescript
await os.billing.relinkBillingProfile({
  companyId: "comp_xxx",
  stripeCustomerId: "cus_new_xxx",
})
```

#### `billing.ensureFeatureSubscription(input)`

确保一个磁盘特性与条纹订阅项目相链接.

```typescript
const result = await os.billing.ensureFeatureSubscription({
  companyId: "comp_xxx",
  featureCode: "ai_credit",
})

console.log(result.action) // 'already_linked' | 'linked_existing' | 'created_new' | 'failed'
```

#### `billing.setUsage(input)`

设置绝对用法( 更正/ 管理) 。 需要一个 `reason` 用于审计.

```typescript
const result = await os.billing.setUsage({
  companyId: "comp_xxx",
  featureCode: "messages",
  absoluteValue: 420,
  reason: "Reconcile after import",
})

console.log({
  previous: result.previousUsage,
  current: result.currentUsage,
  delta: result.delta,
})
```

#### `billing.getUsageHistory(companyId, featureCode, options?)`

用于审计/调试的原始使用事件(不是总卷).

```typescript
const events = await os.billing.getUsageHistory("comp_xxx", "messages", {
  limit: 50,
  eventType: "increment",
})
```

* * *

### 订阅级别( T)

管理订阅级别并应用功能.

#### `tiers.list()`

列出您产品的所有可用级别.

```typescript
const tiers = await os.tiers.list()

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

#### `tiers.get(tierCode)`

获得详细的分级信息,包括花旗价格.

```typescript
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)`

对公司应用分级特征(不含花纹).

```typescript
// 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)`

别名 `tiers.apply()` 采用订阅级.

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

* * *

### 链接

人工管理产品链接.

#### `links.create(input)`

在您的外部 Org ID 和现有的公司之间建立人工链接 .

```typescript
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?)`

删除您产品的所有产品链接 。 重新导入前使用 .

```typescript
// 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`
)
```

* * *

### 上岗

快速客户登机注册.

这个 `onboard()` 方法控件 :

1.  智能公司配对/创建(最佳 `externalOrgId`(中文(简体) )
2.  产品链接
3.  自由级特性访问当 `tierCode: 'free'` (无条纹)
4.  提供离职或订阅身份证时可选的条纹索赔/链接

付费计费设置另行设置: `companies.setupOnboardBilling()` (一心重试.

#### 基本用途

```typescript
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: ["john@acme.com"],
  },
  tierCode: "free",
  contactEmail: "admin@acme.com",
  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' | 'already_linked'
  tierApplied: result.billingStatus?.tierApplied,
})
```

#### 设想1:用户完成的条纹检查

```typescript
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'
```

#### 假想2: 自由等级注册

```typescript
const result = await os.onboard({
  externalOrgId: "org_abc123",
  label: "My Product",
  hints: { companyName: "Acme Inc" },
  tierCode: "free",
  contactEmail: "admin@acme.com",
})

// result.billingStatus.tierApplied = true
```

#### 情景3:您创建条形订阅

```typescript
// 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
```

#### 工作人员创建的工作空间

新公司被贴上标签 `acquisition: 'plg'` (自签. 当工作人员创建 客户端的工作空间(例如从您的管理员仪表板),通过 `origin: "staff"`: 公司获得 没有获取标记,也没有自签名处理(签名默认,重复建议).

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

#### 处理现有客户

```typescript
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 "created":
    console.log("New company created!")
    break
}
```

* * *

## 产品 Webhooks

当ChatarminOS推动公司和产品链接改变您的应用程序时,在处理有效载荷之前,先用SDK验证请求.

```typescript
import { webhooks } from "@chatarmin/os/webhooks"

export async function POST(request: Request) {
  const rawBody = await request.text()

  const event = webhooks.constructEvent(
    rawBody,
    request.headers,
    process.env.OS_WEBHOOK_SIGNING_SECRET!,
  )

  switch (`${event.type}.${event.action}`) {
    case "company.updated":
      // event.data, event.webhookId, event.idempotency_key
      break
  }

  return Response.json({ received: true })
}
```

使用 `ChatarminOS.webhooks.constructEvent` 如果您已经导入了主客户端。 脚踏实地 `event.webhookId` 或者说 `event.idempotency_key`。 。 。 .

* * *

## 常见模式

### 特征

```typescript
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,
})
```

### 条纹订阅流程

```typescript
// 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,
})
```

### 回填历史数据

```typescript
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,
    })),
  })
}
```

* * *

## 类型脚本支持

SDK完全打入了全面的TypeScript定义.

### 导入类型

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

### 路由器类型

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

* * *

## 配置

| 选项 | 类型 | 需求 | 默认 | 说明 |
| --- | --- | --- | --- | --- |
| `apiKey` | `string` | ✅ | —— 说 | OS 管理员面板的 API 密钥 |
| `baseUrl` | `string` | —— 说 | `https://os.chatarmin.com/api/v1` | API 终点 |

```typescript
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:3000/api/v1",
})
```

### 获取您的 API 密钥

1.  (原始内容存档于2017-10-03) (英语). Go to ChatarminOS ~ **设置** → **开发者** → **API 密钥**
2.  点击“ 创建 API 密钥 ”
3.  复制密钥(格式 : `os_sk_xxxxxxxxxxxx`(中文(简体) )
4.  在环境变量中存储

* * *

## 处理错误

SDK在引擎盖下使用tRPC. 错误包括结构化信息 :

```typescript
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)
  }
}
```

### 常见错误代码

| 代码 | 说明 |
| --- | --- |
| `UNAUTHORIZED` | 无效或缺失的 API 密钥 |
| `FORBIDDEN` | 没有访问此资源 |
| `NOT_FOUND` | 未发现公司/地貌 |
| `BAD_REQUEST` | 无效的输入参数 |
| `PRECONDITION_FAILED` | 超过使用限额 |

* * *

## 相关文档

-   **[产品计费API](https://npmcn.com/package/docs/engineering/product-billing-api.md)** 计费读取API, `externalOrgId` 范围界定和预览测试租户
-   **[变动情况](https://npmcn.com/package/%40chatarmin/os/CHANGELOG.md)** ——发行笔记. 下注 `## Unreleased` 当它到达时释放自己 `main` (单位:千美元)`.github/workflows/sdk-release.yml`: `(major)` 编号 : `(minor)` 在它的头上取出起起起落, 否则是一个补丁
-   **[测试-sdk.ts](https://npmcn.com/package/%40chatarmin/os/test-sdk.ts)** ——完整用法示例

* * *

## 支助

-   **电子邮件**数字 : [哈罗 @chatarmin.com](mailto:hello@chatarmin.com)
-   **文档**数字 : [https://os.chatarmin.com/docs (中文(简体) )](https://os.chatarmin.com/docs)

* * *

## 许可证

麻省理工学院

## 常见问题

### @chatarmin/os 是什么？

ChatarminOS 的 SDK 类型安全 - 客户和订阅管理

### 如何安装 @chatarmin/os？

在项目目录运行 npm install @chatarmin/os，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：typescript（^5\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @chatarmin/os 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @chatarmin/os 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @chatarmin/os 可以商用吗？

@chatarmin/os 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @chatarmin/os 的下载量有多少？

根据 npm 官方下载统计，@chatarmin/os 在 2026/10/10 – 2026/11/08 这 30 天内被下载 26,381 次，日均约 879 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @chatarmin/os 还在维护吗？

最新版本 1\.44\.0 发布于 2026/11/08（1 天前）；至今共发布 62 个版本，其中过去 12 个月发布了 62 个；首次发布于 2026/01/08。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

