Skip to main content
本教程以一个文档生成工具为例,演示如何通过 Profy 的 PER_USE 计费模型实现按次收费。

你将构建什么

一个文档生成 SaaS——用户每次执行付费操作时,Profy 自动从其账户扣除相应积分:
  • 生成报告(generate_report)→ 扣 10 积分
  • 导出 PDF(export_pdf)→ 扣 5 积分
  • 生成摘要(generate_summary)→ 扣 3 积分
整个扣费流程由你的应用通过 ProfyApp SDK 调用完成,Profy 保证幂等与原子性。

前置条件

report_event 走 OAuth,只有用户 OAuth token 能调用(不是 API Key)。OAuth token 仅持有 events:write scope——它能上报计费事件,但不能调用 Expert/Chat(那是 sk-pro- API Key 的能力)。

Step 1: 在 Studio 中配置计费事件

进入 Profy Studio → 你的 App → 计费事件,添加以下 Meter:
事件名称一旦创建后不可修改,请使用 snake_case 命名。单价可随时调整,调整后立即生效。运行时可用 list_meters() 读取当前配置的事件与单价。

Step 2: 安装和初始化 SDK

ProfyApp 只持有 App 身份(client_id / client_secret)。用户 token 每次调用时传入——因为一个 App 服务很多用户,各自持有不同的 token。

Step 3: 实现计费上报

用户触发付费操作时,调用 report_event 上报。传入该用户的 OAuthToken,并用 on_refresh 回调持久化轮换后的 token(refresh 每次都会轮换,旧 refresh token 立即作废)。
idempotencyKey 是必填参数(最长 128 字符);event 名最长 100 字符。SDK 未传时会自动生成一个,但重试必须复用同一个 key(见 Step 5)。
响应结构:
扣费金额由服务端根据 Meter 的单价决定——请求体没有 amount/units 字段。想在客户端展示单价,用 list_meters() 读取。

Step 4: 用 Meter 展示单价 + 从响应追踪余额

平台没有独立的余额查询端点。正确做法是:用 list_meters()(公开,无需 token)拿到单价用于前端展示;用户余额则从每次 report_event 响应的 balance_remaining 追踪,并始终处理 InsufficientBalanceError(402)。
不要在扣费前”预检余额”——没有余额端点,且并发操作会让预检结果失效。直接上报、捕获 InsufficientBalanceError 才是正确姿势。

Step 5: 处理扣费失败

错误按 HTTP 状态码分类,都继承自 ProfyApiError(带 .statusCode / .status_code.body)。
错误处理策略:
report_event 内置了 token 轮换处理:access token 过期时(配了 on_refresh)会自动刷新一次并回调,401 时也会反应式刷新重试一次。你只需在 on_refresh 里持久化新 token。

Step 6: 幂等性与安全重试

idempotencyKey 保证同一业务操作不会被重复扣费。请求超时或网络抖动时,用同一个 key 安全重试。
重试时必须复用同一个 idempotencyKey。每次重试生成新 key 会导致重复扣费。

计费事件设计指南

命名规范

  • 使用 snake_case,以动词开头:generate_export_analyze_
  • 避免泛化命名(如 actionevent),长度建议 ≤ 32 字符

粒度决策

一条经验法则:如果用户会把两个操作理解为”一件事”,它们应该合并为一个事件。如果用户会问”为什么这次扣了这么多”,说明粒度需要拆细。

常见问题

Q: 幂等键重复会怎样? API 返回 idempotent_replay: true,不会重复扣费。charged 值为首次扣费金额。 Q: 怎么在扣费前知道余额? 平台没有余额查询端点。用每次 report_event 响应里的 balance_remaining 追踪,并处理 InsufficientBalanceError Q: metadata 会被存下来吗? metadata 字段被接受但当前不会被持久化或返回,不要依赖它做业务判断——它仅供未来扩展。 Q: 单价修改后已发出的请求按哪个价格? 按请求到达时的最新单价计算。修改立即生效,无过渡期。 Q: refresh token 会过期吗? 90 天有效,且每次刷新都会轮换(旧的立即作废)。用 on_refresh 持久化新 token,否则 App 刷一次就把自己锁死。

下一步

SDK 快速开始

OAuth 授权与基础事件上报

Token 管理

OAuth 授权码流程与 token 轮换持久化

调用平台专家

在你的 App 中嵌入 AI 专家能力

API 参考

Events API 完整端点文档