跳到正文

指南

配方:API 额度

为 API 或 AI 功能出售预付额度,每次请求扣一个。余额不足时返回 402 和充值链接。

买家预先购买额度包;每次请求消耗若干额度。记账由 Perly Pay 负责:扣减是一次原子调用,余额不会变成负数,每位买家都有自己的充值页。绝不自动扣款 — 额度用完时由买家充值。额度的全部内容见 Sell credits;这里是围绕它的配方。

配合助手:Perly Pay 插件的 sell-credits 技能会在你的项目中实现这个配方。可运行的示例是插件仓库中的 examples/api-credits(MIT)。

如何运作

  1. 1

    额度包

    一个商品和一个价格,带 model: "credit_pack"、以分为单位的 unit_amount 和 credits。每种模式设置一次。

  2. 2

    你的用户就是客户

    用 external_id(你的用户 ID)创建一次;之后 credits.* 直接接受这个 ID。

  3. 3

    充值

    credits.topUpUrl(userId) 是买家专属页面:选择额度包并付款。每个已付额度包都会增加额度。

  4. 4

    每次请求扣减

    先 credits.consume(userId, cost, { idempotencyKey }),再干活。用同一个键重试会返回第一次扣减,所以每个请求的键由你的服务器生成,绝不取自调用方。

  5. 5

    不足?

    insufficient_credits(409)不扣任何额度:返回 402 和充值页,而不是 500。

Spend one request's credits
try {
  await pay.credits.consume(userId, cost, { product: PRODUCT, action: "api", idempotencyKey: `req-${userId}-${requestId}` });
} catch (e) {
  if (e.code !== "insufficient_credits") throw e;
  return reply(402, { top_up: await pay.credits.topUpUrl(userId, { product: PRODUCT }) });
}
// now do the work

运行示例

  1. 1

    安装

    在 examples/api-credits 中运行 npm install(Node 20.12+)。

  2. 2

    密钥

    把 .env.example 复制为 .env,在 PERLY_PAY_SECRET_KEY 中填入测试密钥(sk_test_…)。

  3. 3

    准备

    npm run setup 用你的密钥创建商品和价格,并打印它们的 ID 供 .env 使用。

  4. 4

    启动

    按其 README 运行 npm start(或 npm run dev)。

  5. 5

    无需钱包即可付款

    调用 POST /v1/shout(402),打开 POST /top-up 给出的页面,选一个额度包,在账单上点 Simulate payment,再调用一次:200,X-Credits-Remaining: 499。

陷阱

  • 扣减时不带幂等键:重试的请求会扣两次。
  • 扣减键取自客户端发送的内容(Idempotency-Key 请求头):同一个键会把第一次扣减当作成功返回,客户端不付钱就又得到了结果。
  • 先查余额、再分两步扣减。consume 本身就不会扣成负数;余额只用于显示。
  • 先干活、后扣减。应该反过来:先扣减。
  • 用正式密钥配测试 ID。商品、价格和 Webhook 都属于某一种模式:上线前用 sk_live_… 重做一遍设置。