mcpField
P
paddle-catalog-setup

paddle-catalog-setup

github.com/paddlehq其他9110 次安装4 天前更新
代码仓库

关于 paddle-catalog-setup

面向 Paddle 集成开发者的设置技能,指导创建其他 Paddle 工作流所需的产品和价格。它要求先确认目录、税务、计费、试用、币种和环境选项,不凭空猜测。

主要功能

  1. 01引导规划产品与价格
  2. 02提供税务类别和计费指导
  3. 03支持订阅、一次性及试用定价
  4. 04优先选择沙盒环境
  5. 05支持 Paddle MCP、CLI、SDK 或控制台

适用场景

  1. 01为新集成创建 Paddle 商品目录
  2. 02添加计费周期或一次性价格
  3. 03设置试用和区域定价

MCP 相关

有 Paddle MCP 服务工具时,技能会用 `search` 确认 API 方法,再用 `execute` 创建产品和价格。除非明确要求使用线上环境,否则优先选择沙盒。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/paddlehq/paddle-agent-skills --skill paddle-catalog-setup

安装后在 Claude Code 中输入/paddle-catalog-setup确认已加载。

详细介绍

创建 Paddle 产品和价格

何时使用此技能

用户正在开始集成 Paddle,而其账户中还没有其他 Paddle 技能(checkout-web、pricing-pages、sandbox-testing、webhooks)所依赖的产品和价格。使用此技能创建它们。

这通常是每个项目只需进行一次的设置。目录创建完成后,就不需要再使用此技能,除非用户想添加新的产品或价格。

你要配置的内容——先与用户确认

创建任何内容之前,先与用户确认以下事项。不要猜测。

  • 产品与价格。
    • 产品是售卖的内容(“Pro 套餐”、“终身许可证”)。
    • 价格是收费方式(每月 10 美元、每年 96 美元、一次性支付 999 美元)。
    • 一个产品可以有多个价格,通常每个计费周期对应一个价格。
    • 不同市场可以设置不同的价格覆盖。
  • 税务类别(按产品设置)。从下表中选择。软件即服务默认使用 saas,可下载软件默认使用 standard,并在创建后向用户说明所选类别以供确认。其他类别需先获得批准,见下文。
  • 计费模式(按价格设置)。定期计费(订阅)需要计费周期(例如 month / year):MCP 请求体参数中为 billing_cycle,SDK 中为 billingCycle;一次性价格不填写此项。试用期仅适用于订阅——API 会拒绝一次性价格上的试用期。
  • 试用类型(仅适用于定期价格)。询问用户试用是免费、付费还是免绑卡。无效的试用设置会返回 400 bad_request,并在 errors 中指出有问题的字段。
    • 免费——trial_period: { interval, frequency }。客户在结账时添加支付方式,试用结束前无需付费。
    • 付费——添加试用费用 trial_period.unit_price({ amount, currency_code })。其币种必须与基础价格一致。如果价格设置了 unit_price_overrides,则需为每个覆盖项添加 trial_period.unit_price_overrides 条目,并使用相同的 country_codes。请使用 MCP(方法 1)、CLI(方法 2)或直接调用 API;Node SDK 目前尚不支持试用定价。
    • 免绑卡——设置 trial_period.requires_payment_method: false,客户无需支付方式即可开始试用。免绑卡试用目前处于早期访问阶段;如果没有访问权限,API 会返回 400 bad_request。试用不能同时为付费和免绑卡。
  • 价格名称和数量。 description 为必填项,仅供内部使用,客户不会看到。name 为可选项,长度为 1–150 个字符,会显示在客户结账页面和发票上,例如“月付”。quantity 用于限制此价格可购买的数量,默认范围为 1–100;如需设置其他范围(例如座位数),请设置 quantity: { minimum, maximum }。
  • 币种和金额。 单价金额(MCP 中为 unit_price.amount,SDK 中为 unitPrice.amount)是以币种最小单位表示的字符串。USD/EUR/GBP 使用美分等最小单位("1000" = 10.00 美元)。零小数位币种使用整数单位——JPY、KRW、VND 和 CLP("1200" = ¥1,200 / ₩1,200 / CLP$1,200,而不是 ¥12 等)。如需查询任意币种,请读取 client.currencies.list()(MCP;返回普通数组)中的 decimal_places,或调用公开的 GET /currencies 端点。
  • 环境。 开发期间默认使用沙盒环境。沙盒和生产环境完全独立,一个环境中的 pro_... 和 pri_... ID 在另一个环境中不存在。使用生产环境前,请先询问用户。

ID 格式如 pro_01h...(产品)和 pri_01h...(价格)。你需要价格 ID 来接入用户的应用,因此请在创建后记录这些 ID。

税务类别
类别适用范围是否需要审批?
saas允许用户通过互联网连接并使用在线或基于云的应用程序的产品。否
standard预先编写的软件产品,可下载并安装到本地设备上。否
digital-goods以预付款购买、不可定制的数字文件或媒体(非软件),无需交付任何实体产品即可访问。是
ebooks以永久使用权形式出售给客户的数字图书和教育材料。是
implementation-services代表客户远程配置、设置和集成软件。是
professional-services涉及运用你在软件产品方面的专业技能和专门知识的服务。是
software-programming-services可用于定制和白标化软件产品的服务。是
training-services与软件产品相关的培训和教育服务。是
website-hosting用于存储个人或企业信息、资产或知识产权的云存储服务。是

只有 saas 和 standard 无需审批即可使用。用户可在其正式账户的 Paddle > My account > Settings > Taxable categories 中申请其他类别。创建使用未获批准类别的产品会返回 product_tax_category_not_approved。

选择你的方式

选择当前可用的优先级最高的方式:

  1. Paddle MCP 服务 — 如果你的工具集中有来自 paddle-sandbox(或 paddle-live)MCP 服务的 search 和 execute 工具,请使用它们。速度最快,无需用户运行代码,结果即时返回。始终优先选择此方式。
  2. Paddle CLI — 如果没有 MCP,但已安装 paddle,请使用用户已保存的登录信息运行命令。无需向项目添加代码。
  3. Node SDK 种子脚本 — 如果以上方式都不可用,但用户有 PADDLE_API_KEY(或可以生成一个),请生成种子脚本供用户运行。可重复执行,并可进行版本控制。
  4. 控制面板(手动操作) — 如果以上方式都不可行,请逐步说明用户需要点击的位置。

如果某种方式中途失败(例如,SDK 调用因 API 密钥权限不足而返回 forbidden),请改用下一种方式,而不要重试。

如果用户尚未安装 Paddle MCP 服务,请将其作为建议告知用户,并提供 Paddle MCP 服务安装指南。

方法 1:Paddle MCP 服务

检查你是否可以使用 paddle-sandbox(或 paddle-live)提供的 search 和 execute 工具。如果可以,请使用它们。

每个 Paddle MCP 服务提供三个工具(search、execute、report_missing_tool)。工作流程:调用 search 确认准确的方法名和参数结构,然后调用 execute,并传入一个会调用 client.<resource>.<operation>(...) 的异步函数。方法路径使用 camelCase(client.clientTokens.create、client.pricingPreview.preview)。请求体参数和响应字段使用 snake_case(tax_category、product_id、unit_price、currency_code)。列表方法返回 { pagination: { hasMore, estimatedTotal }, <resource>: [...] },而不是 data。数组的键是资源的 API 路径段;如果方法路径使用 camelCase,该键就使用 kebab-case:(await client.products.list()).products、(await client.clientTokens.list())["client-tokens"]。当 pagination.hasMore 为 true 时,使用 { after: "<last_id>" } 翻页,而不是调用 .next()。未分页的列表(例如 client.currencies.list())会返回普通数组。单实体方法会返回该实体。在一次 execute 中串联多步工作流;不同调用之间不会保留变量。硬性限制:每次 execute 最多调用 50 次 API、超时时间为 30 秒,代码最多 32,000 个字符。

除非用户明确要求使用正式环境,否则默认使用 paddle-sandbox。

  1. 与用户确认产品详情(名称、税务类别和要创建的价格)。
  2. 使用类似 "products create" 和 "prices create" 的查询调用 search,确认当前的方法名和参数结构。
  3. 使用一个异步函数调用 execute,一次性创建产品及其所有价格。在一次 execute 中串联操作,可避免多次往返,并让相关操作保持原子性。
  4. 将所有创建的 ID 告知用户,以便他们粘贴到应用中。

execute 载荷示例——一个产品、月付价和年付价,以及带试用期的月付价:

async (client) => {
  const product = await client.products.create({
    name: "Pro",
    tax_category: "saas",
    description: "For scaling teams.",
  });
  const monthly = await client.prices.create({
    product_id: product.id,
    description: "Pro monthly USD",
    name: "Monthly",
    unit_price: { amount: "1000", currency_code: "USD" },
    billing_cycle: { interval: "month", frequency: 1 },
    trial_period: { interval: "day", frequency: 14 },
  });
  const yearly = await client.prices.create({
    product_id: product.id,
    description: "Pro yearly USD",
    name: "Yearly",
    unit_price: { amount: "9600", currency_code: "USD" },
    billing_cycle: { interval: "year", frequency: 1 },
  });
  return { product_id: product.id, monthly_id: monthly.id, yearly_id: yearly.id };
};

对于一次性价格(终身许可证等),请移除 billing_cycle 和 trial_period:

const lifetime = await client.prices.create({
  product_id: product.id,
  description: "Pro lifetime",
  unit_price: { amount: "29900", currency_code: "USD" },
});

对于付费试用,请在 trial_period 中添加 unit_price(如果价格有覆盖项,还需添加 unit_price_overrides——请参阅上文“试用类型”):

trial_period: {
  interval: "day",
  frequency: 14,
  unit_price: { amount: "100", currency_code: "USD" }, // $1.00 for the 14-day trial
},

对于区域定价,请添加 unit_price_overrides——所有字段均使用 snake_case,包括内部字段名:

unit_price_overrides: [
  {
    country_codes: ["DE", "FR", "IT", "ES", "NL"],
    unit_price: { amount: "900", currency_code: "EUR" },
  },
  { country_codes: ["GB"], unit_price: { amount: "800", currency_code: "GBP" } },
  { country_codes: ["JP"], unit_price: { amount: "1200", currency_code: "JPY" } },
];

如果无法使用 MCP 的 search / execute 工具,请改用方法 2。

方法 2:Paddle CLI

检查是否已安装 paddle(paddle --version)并登录(paddle whoami --environment sandbox)。如果是,就使用它。

Paddle CLI(paddle,v0.2.0 或更高版本)使用用户保存的登录信息,在终端中执行 Paddle API 操作。资源命令与 API 参考中的操作相对应:paddle products create 就是“创建产品”。运行 paddle <resource> --help 查找命令;在创建或更新命令中添加 --schema 可查看请求正文;对于没有对应命令的端点,可使用 paddle api <path>。它默认在实时账户中运行,因此除非用户正在使用实时环境,否则请传入 --environment sandbox。Agent 运行命令时,命令会返回 API 的 JSON(data、meta),其中 meta.environment 会注明所用账户。取消和删除命令需要 --confirm <id>。只有在用户同意执行特定取消或删除操作后,才添加此参数;绝不能用它来绕过用户的拒绝。paddle api 的写入操作完全不会经过确认,因此也应同样处理。退出代码 5 表示 403:权限缺失,或登录的是另一个账户。退出代码 7 表示验证错误。如果 paddle whoami 显示未登录,请让用户自行运行 paddle login(sandbox 需要 API 密钥:paddle login --environment sandbox --api-key …),绝不要在聊天中索要密钥。使用 OAuth 登录的实时账户可以执行该用户 Paddle 角色所允许的任何更改,因此请逐项说明每项实时环境更改,并在运行前等待用户同意。对于 CI/CD,请将仅包含必要权限的实时 API 密钥设为 PADDLE_API_KEY。安装方法请参阅 Paddle CLI。

请求正文与上述 MCP 示例使用相同的 snake_case JSON,因此试用、一次性和区域定价方案均可直接使用。先创建产品,再使用产品 ID 创建每个价格。--jq '.data.id' 只会打印新 ID:

paddle --environment sandbox products create --jq '.data.id' \
  --json '{"name": "Pro", "tax_category": "saas", "description": "For scaling teams."}'

paddle --environment sandbox prices create --jq '.data.id' --json '{
  "product_id": "pro_01h...",
  "description": "Pro monthly USD",
  "name": "Monthly",
  "unit_price": { "amount": "1000", "currency_code": "USD" },
  "billing_cycle": { "interval": "month", "frequency": 1 },
  "trial_period": { "interval": "day", "frequency": 14 }
}'

将所有创建的 ID 返回给用户。如果用户之后想重新运行设置(例如在新的 sandbox 账户中),请将命令保存为其代码库中的脚本。如果命令以代码 5 退出,说明登录缺少 product.write 或 price.write 权限:请用户将这些权限添加到 API 密钥,或改用方法 4。

方法 3:Node SDK 种子脚本

当用户已有(或可以安装)@paddle/paddle-node-sdk 和 PADDLE_API_KEY 时使用此方法。由你编写脚本,用户运行脚本。

  1. 确认用户已在环境中设置 PADDLE_API_KEY。如果没有,请指引他们前往 sandbox 控制台中的 Paddle > My account > Settings > Authentication,并让他们在 API keys 选项卡中创建密钥,至少授予 product.write 和 price.write 权限。
  2. 如果项目中尚未添加,请将 @paddle/paddle-node-sdk 添加到项目中(npm install @paddle/paddle-node-sdk)。
  3. 编写种子脚本,并让用户运行一次。
  4. 从输出中获取打印出的 ID,并用它们更新用户的应用配置。

模板:

// scripts/seed-paddle-catalog.ts
import { Environment, Paddle } from "@paddle/paddle-node-sdk";

const paddle = new Paddle(process.env.PADDLE_API_KEY!, {
  environment: Environment.sandbox, // change to .production for live
});

async function seed() {
  const pro = await paddle.products.create({
    name: "Pro",
    taxCategory: "saas",
    description: "For scaling teams.",
  });

  const monthly = await paddle.prices.create({
    productId: pro.id,
    description: "Pro monthly USD",
    name: "Monthly",
    unitPrice: { amount: "1000", currencyCode: "USD" }, // 1000 cents = $10.00
    billingCycle: { interval: "month", frequency: 1 },
    trialPeriod: { interval: "day", frequency: 14 },
  });

  const yearly = await paddle.prices.create({
    productId: pro.id,
    description: "Pro yearly USD",
    name: "Yearly",
    unitPrice: { amount: "9600", currencyCode: "USD" },
    billingCycle: { interval: "year", frequency: 1 },
  });

  console.log(
    JSON.stringify({ productId: pro.id, monthlyId: monthly.id, yearlyId: yearly.id }, null, 2),
  );
}

seed().catch((e) => {
  console.error(e);
  process.exit(1);
});

运行命令:npx tsx scripts/seed-paddle-catalog.ts。

一次性价格(终身许可证等)——删除 billingCycle 和 trialPeriod:

await paddle.prices.create({
  productId: pro.id,
  description: "Pro lifetime",
  unitPrice: { amount: "29900", currencyCode: "USD" },
});

区域覆盖价格——添加 unitPriceOverrides:

unitPriceOverrides: [
  { countryCodes: ["DE", "FR", "IT", "ES", "NL"], unitPrice: { amount: "900", currencyCode: "EUR" } },
  { countryCodes: ["GB"], unitPrice: { amount: "800", currencyCode: "GBP" } },
  { countryCodes: ["JP"], unitPrice: { amount: "1200", currencyCode: "JPY" } },
],

付费试用——Node SDK 的 trialPeriod 类型目前尚不支持 unitPrice,且价格响应会将其省略。请使用 MCP(方法 1)、CLI(方法 2)或直接调用 POST /prices 创建付费试用价格。

如果脚本因 forbidden 或 unauthorized 而失败,说明 API 密钥缺少所需的权限范围——请用户重新生成密钥,并授予 product.write 和 price.write 权限。如果脚本失败是因为用户无法或不愿安装 SDK,请改用方法 4。

方法 4:控制面板(手动)

最后手段。仅当 MCP、CLI 和 SDK 路径都受阻时使用。告诉用户操作步骤,然后请他们分享 ID。

告诉用户:

  1. 登录沙盒控制面板(如果要上线,请登录正式环境)。
  2. 前往 Paddle > Catalog > Products,然后点击 New product。填写:
    • Name — 例如“Pro”(这是用户在结账时看到的名称)。
    • Tax category — <the value you agreed on above>。
    • 描述、图标 — 可选。
  3. 保存产品。
  4. 在新建的产品中,点击 New price。填写:
    • Description — 内部标签(例如“Pro monthly USD”)。
    • Type — Recurring(订阅)或 One-time(一次性)。
    • Billing cycle(仅限定期付款)— Monthly、Yearly、Weekly、Daily 或 Custom。
    • Trial period(仅限定期付款)— 可选。
    • Amount — 金额 + 货币(例如 10.00 USD)。
    • Regional prices — 可选,按市场设置价格覆盖值。
  5. 保存价格。对每个所需价格重复此操作。
  6. 创建所有价格后,从价格详情面板复制 pri_... ID 并发给我。

用户分享 ID 后,更新其应用配置(常量文件、环境变量,或你决定存放价格 ID 的位置)。

验证

无论使用哪种方法,在声明此技能已完成之前:

  1. 确认产品和价格已创建。 通过 MCP:调用一次 execute:client.products.list({ include: ["prices"] })。通过 CLI:paddle --environment sandbox products list --include prices。通过 SDK:paddle.products.list({ include: ["prices"] })。或者请用户在控制面板中检查 Paddle > Catalog > Products。
  2. 确认你报告的 ID 相符。 通过 MCP:对每个新产品调用 client.products.get(productId, { include: ["prices"] })(注意 productId 是位置路径参数)。通过 SDK:paddle.products.get(id, { include: ["prices"] })。检查名称和税务类别。
  3. 建议下一步。 建议用户接下来完成 checkout-web,并使用一个新价格 ID,以确认目录在结账流程中确实可用。

常见问题

  • 在错误的环境中创建。 沙盒和生产环境的目录完全分离。使用远程 MCP 时,服务名称决定环境——沙盒使用 paddle-sandbox,生产环境使用 paddle-live。paddle-sandbox 使用 pdl_sdbx_... API 密钥进行身份验证;paddle-live 则在浏览器中通过 OAuth 授权(也可使用正式环境 API 密钥)。使用 SDK 时,对应的是 Environment.sandbox 和 Environment.production。创建前务必确认环境。
  • 混淆金额单位。 unit_price.amount(MCP)/ unitPrice.amount(SDK)是以货币最小单位表示的字符串。"1000" 表示 $10.00,不是 $1000。零小数位货币(JPY、KRW、VND、CLP)以整单位表示——"1200" 表示 ¥1,200 / ₩1,200 / CLP$1,200,而不是 ¥12 等。
  • 忘记在价格中填写产品 ID。 client.prices.create()(MCP)和 paddle.prices.create()(SDK)都需要父产品的 ID——MCP 请求体参数中的 product_id,SDK 中的 productId。先创建产品并记录其 id,然后将其传给每个价格。
  • 在一次性价格上设置试用期。 不允许这样做——试用期仅适用于订阅。API 会拒绝此请求。如果没有计费周期,请移除 trial_period(MCP)/ trialPeriod(SDK)。
  • 周期性价格未设置计费周期。 如果不设置 billing_cycle(MCP)/ billingCycle(SDK),价格就会被创建为一次性价格。订阅务必设置 { interval: "month", frequency: 1 }(或类似值)。
  • 在 MCP 的 execute 代码中混用 camelCase 和 snake_case。 方法路径使用 camelCase(client.clientTokens.create、client.pricingPreview.preview),但请求体参数和响应字段使用 snake_case(tax_category、product_id、unit_price、currency_code)。SDK 从头到尾都使用 camelCase——不要把这种惯例带入 execute 代码,也不要把 snake_case 惯例带入 SDK 代码。
  • 将有依赖关系的调用拆分到多个 execute 调用中。 变量不会在不同的 execute 调用之间保留,因此传递 ID 时,需要先返回 ID,再在下一次调用中重新传入。在一个异步函数中串联有依赖关系的操作(产品 → 价格 → 覆盖项),并在最后返回 ID。
  • 使用地区覆盖价格时未设置合理的基础价格。 对于未设置覆盖价格的国家/地区,客户需支付基础价格——只有用户在 Paddle > My account > Settings > Currencies 中启用了对应货币,才会将该价格转换为当地货币。请选择适合作为备用价格的基础货币。
  • 缺少写入权限。 远程 MCP 会继承其身份验证方式对应的权限。如果 client.products.create() 在 paddle-sandbox 上返回 forbidden,说明 API 密钥缺少 product.write / price.write 权限——请用户前往 Paddle > My account > Settings > Authentication,重新生成包含这些权限的密钥。如果通过 OAuth 连接 paddle-live,连接初始为只读,因此在用户前往 Paddle > Connectors > MCPs 授予写入权限之前,写入操作返回 forbidden 属于预期情况。此处的权限受其 Paddle 用户角色限制。
  • 将 ID 粘贴到用户代码中却不告知用户。 务必将新 ID 告知用户;由用户(或经用户批准后的你)明确提交更改。

相关文档

评论

支持 Markdown