@chatarmin/os (中文(简体) )
Type-security SDK for ChatarminOS——为B2B SaaS管理客户,订阅,特性访问,和计费的全能平台.
特征
- 🏢 公司管理 - 创建、链接和管理客户公司
- 🎫 订阅级别 - 界定带有特征和条纹定价的等级
- ✨ 特性访问 - 检查应享权利并强制执行使用限制
- 📊 用法跟踪 ——用"一能"支持计算账单
- 💳 条纹融合 ——报销结账会话,链接订阅
- 🔗 智能链接 ——智能公司按域名/名/电子邮件进行匹配
- 👥 联系人同步 ——各公司频繁增加联系人
- 🚀 统一登入 ——在一个API呼叫中完成设置
目录
安装
pnpm add @chatarmin/os
# or
npm install @chatarmin/os
# or
yarn add @chatarmin/os
快速启动
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' | 'already_linked'
API 参考
公司
管理客户公司及其与您产品的联系.
companies.get(input)
找一家由你的外部组织 ID或ChatarminOS公司ID.
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)
创建一新公司,并与您的产品链接.
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)
更新公司元数据(如回填历史日期).
await os.companies.update({
companyId: "uuid-here",
createdAt: "2023-06-01T00:00:00.000Z",
})
联系人
管理与公司有关的人员.
contacts.create(input)
创建或更新单个联系人.
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)
批量创建或更新多个联系人. 建议入职.
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?)
列出公司的联系人 .
// 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 详细情况.
features.check(input)
请检查access-date=中的日期值 (帮助) 公司能否访问特定功能.
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)
列出公司的所有功能及其接入状态.
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 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 获取所有特性 .
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 检查特定特性 .
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- 要求/答复的完整形状os.billing.*方法.
billing.trackUsage(input)
用于调制功能的音轨用法 .
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取出会话.
// 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订阅链接到公司.
// 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 实例 用于完整行走+样本反应.
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)
合并计费页有效载荷:公司、计费概况、主要订阅和最近的发票.
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
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
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
await os.contacts.update({
companyId: company.id,
email: '[email protected]',
role: 'Owner',
})
await os.contacts.unlink({ companyId: company.id, email: '[email protected]' })
unlink 取消公司的联系人。 只有在没有其他公司继续使用时,个人记录才会被删除.
billing.listClientUsage(input)
在一个时期内对每个关联客户端的使用. 更喜欢循环 getUsage 给管理员看看. startingOn 包容性, endingBefore 这是独家的,最长366天。 API 键将调用范围限制到其产品; 设置 includeAllProducts: true 将每个产品都纳入该组织。 可选 companyIds 财务报告和审定财务报表 externalOrgIds 缩小结果。 奥米 featureCode 以返回所有使用过的特性.
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 解释一下可能缺少什么.
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),设置费和其他一次性收费从不计数.
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——使用范围与产品链接.
// 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 看到了吗 特性标识符。 。 。 .
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 + 日期).
响应形状 :
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' - 总期间:
{
"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' 每日图表桶:
{
"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 }:
{
"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
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。 。 。 .
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?)
列出公司发票(不包括汇票/票).
const { invoices } = await os.billing.listInvoices("comp_xxx", { limit: 24 })
billing.getPaymentMethod(companyIdOrInput)
已解决的收费情况付款方法摘要.
const { billingProfile } = await os.billing.getPaymentMethod("comp_xxx")
billing.createPortalSession(input)
开放Frede客户端 用于管理收费流量. returnUrl 必须在允许的产品主机上(products.metadata.billing.returnUrlHosts) (中文(简体) ).
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.
const { hostedInvoiceUrl } = await os.billing.resolveInvoicePaymentUrl({
companyId: "comp_xxx",
invoiceId: "inv_xxx",
})
billing.listPastDuePaymentUrls(companyIdOrInput)
列出过期的发票以及付款地址.
const { items } = await os.billing.listPastDuePaymentUrls("comp_xxx")
billing.sendPastDueInvoice(input)
通过 Strape 电子邮件过期发票( 当收集方法为 send_invoice) (中文(简体) ).
await os.billing.sendPastDueInvoice({
companyId: "comp_xxx",
invoiceId: "inv_xxx",
})
billing.syncCompanyFromStripe(input)
调取Frede的帐单、订阅和功能链接.
const result = await os.billing.syncCompanyFromStripe({
companyId: "comp_xxx",
stripeCustomerId: "cus_xxx",
})
console.log({
subscriptionsSynced: result.subscriptionsSynced,
featuresLinked: result.featuresLinked,
})
billing.relinkBillingProfile(input)
将公司开具的开票情况换成新的"条纹"客户(破坏性).
await os.billing.relinkBillingProfile({
companyId: "comp_xxx",
stripeCustomerId: "cus_new_xxx",
})
billing.ensureFeatureSubscription(input)
确保一个磁盘特性与条纹订阅项目相链接.
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 用于审计.
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?)
用于审计/调试的原始使用事件(不是总卷).
const events = await os.billing.getUsageHistory("comp_xxx", "messages", {
limit: 50,
eventType: "increment",
})
订阅级别( T)
管理订阅级别并应用功能.
tiers.list()
列出您产品的所有可用级别.
const tiers = await os.tiers.list()
for (const tier of tiers) {
console.log(`${tier.name} (${tier.code})`)
}
// ['Free', 'Pro', 'Enterprise']
tiers.get(tierCode)
获得详细的分级信息,包括花旗价格.
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 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() 采用订阅级.
await os.subscriptions.create("pro", {
companyId: "comp_xxx",
features: {
ai_credit: { included_quantity: 500 },
},
})
链接
人工管理产品链接.
links.create(input)
在您的外部 Org ID 和现有的公司之间建立人工链接 .
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?)
删除您产品的所有产品链接 。 重新导入前使用 .
// 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() 方法控件 :
- 智能公司配对/创建(最佳
externalOrgId(中文(简体) ) - 产品链接
- 自由级特性访问当
tierCode: 'free'(无条纹) - 提供离职或订阅身份证时可选的条纹索赔/链接
付费计费设置另行设置: companies.setupOnboardBilling() (一心重试.
基本用途
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' | 'already_linked'
tierApplied: result.billingStatus?.tierApplied,
})
设想1:用户完成的条纹检查
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: 自由等级注册
const result = await os.onboard({
externalOrgId: "org_abc123",
label: "My Product",
hints: { companyName: "Acme Inc" },
tierCode: "free",
contactEmail: "[email protected]",
})
// result.billingStatus.tierApplied = true
情景3:您创建条形订阅
// 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": 公司获得
没有获取标记,也没有自签名处理(签名默认,重复建议).
const result = await os.onboard({
externalOrgId: "org_abc123",
label: "My Product",
hints: { companyName: "Acme Inc" },
origin: "staff",
})
处理现有客户
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验证请求.
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。 。 。 .
常见模式
特征
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,
})
条纹订阅流程
// 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,
})
回填历史数据
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定义.
导入类型
import { ChatarminOS } from "@chatarmin/os"
import type {
ChatarminOSConfig,
CreateCompanyInput,
ContactInput,
FeatureCheckInput,
FeatureSetAccessInput,
TrackUsageInput,
OnboardInput,
OnboardResult,
ApplyTierInput,
ClaimCheckoutInput,
LinkSubscriptionInput,
} from "@chatarmin/os"
路由器类型
import type { AppRouter } from "@chatarmin/os"
配置
| 选项 | 类型 | 需求 | 默认 | 说明 |
|---|---|---|---|---|
apiKey | string | ✅ | —— 说 | OS 管理员面板的 API 密钥 |
baseUrl | string | —— 说 | https://os.chatarmin.com/api/v1 | API 终点 |
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 密钥
- (原始内容存档于2017-10-03) (英语). Go to ChatarminOS ~ 设置 → 开发者 → API 密钥
- 点击“ 创建 API 密钥 ”
- 复制密钥(格式 :
os_sk_xxxxxxxxxxxx(中文(简体) ) - 在环境变量中存储
处理错误
SDK在引擎盖下使用tRPC. 错误包括结构化信息 :
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 计费读取API,
externalOrgId范围界定和预览测试租户 - 变动情况 ——发行笔记. 下注
## Unreleased当它到达时释放自己main(单位:千美元).github/workflows/sdk-release.yml:(major)编号 :(minor)在它的头上取出起起起落, 否则是一个补丁 - 测试-sdk.ts ——完整用法示例
支助
- 电子邮件数字 : 哈罗 @chatarmin.com
- 文档数字 : https://os.chatarmin.com/docs (中文(简体) )
许可证
麻省理工学院