关于 paddle-catalog-setup
面向 Paddle 集成开发者的设置技能,指导创建其他 Paddle 工作流所需的产品和价格。它要求先确认目录、税务、计费、试用、币种和环境选项,不凭空猜测。
主要功能
- 01引导规划产品与价格
- 02提供税务类别和计费指导
- 03支持订阅、一次性及试用定价
- 04优先选择沙盒环境
- 05支持 Paddle MCP、CLI、SDK 或控制台
适用场景
- 01为新集成创建 Paddle 商品目录
- 02添加计费周期或一次性价格
- 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。
选择你的方式
选择当前可用的优先级最高的方式:
- Paddle MCP 服务 — 如果你的工具集中有来自
paddle-sandbox(或paddle-live)MCP 服务的search和execute工具,请使用它们。速度最快,无需用户运行代码,结果即时返回。始终优先选择此方式。 - Paddle CLI — 如果没有 MCP,但已安装
paddle,请使用用户已保存的登录信息运行命令。无需向项目添加代码。 - Node SDK 种子脚本 — 如果以上方式都不可用,但用户有
PADDLE_API_KEY(或可以生成一个),请生成种子脚本供用户运行。可重复执行,并可进行版本控制。 - 控制面板(手动操作) — 如果以上方式都不可行,请逐步说明用户需要点击的位置。
如果某种方式中途失败(例如,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。
- 与用户确认产品详情(名称、税务类别和要创建的价格)。
- 使用类似
"products create"和"prices create"的查询调用search,确认当前的方法名和参数结构。 - 使用一个异步函数调用
execute,一次性创建产品及其所有价格。在一次execute中串联操作,可避免多次往返,并让相关操作保持原子性。 - 将所有创建的 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 时使用此方法。由你编写脚本,用户运行脚本。
- 确认用户已在环境中设置
PADDLE_API_KEY。如果没有,请指引他们前往 sandbox 控制台中的 Paddle > My account > Settings > Authentication,并让他们在 API keys 选项卡中创建密钥,至少授予product.write和price.write权限。 - 如果项目中尚未添加,请将
@paddle/paddle-node-sdk添加到项目中(npm install @paddle/paddle-node-sdk)。 - 编写种子脚本,并让用户运行一次。
- 从输出中获取打印出的 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。
告诉用户:
- 登录沙盒控制面板(如果要上线,请登录正式环境)。
- 前往 Paddle > Catalog > Products,然后点击 New product。填写:
- Name — 例如“Pro”(这是用户在结账时看到的名称)。
- Tax category —
<the value you agreed on above>。 - 描述、图标 — 可选。
- 保存产品。
- 在新建的产品中,点击 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 — 可选,按市场设置价格覆盖值。
- 保存价格。对每个所需价格重复此操作。
- 创建所有价格后,从价格详情面板复制
pri_...ID 并发给我。
用户分享 ID 后,更新其应用配置(常量文件、环境变量,或你决定存放价格 ID 的位置)。
验证
无论使用哪种方法,在声明此技能已完成之前:
- 确认产品和价格已创建。 通过 MCP:调用一次
execute:client.products.list({ include: ["prices"] })。通过 CLI:paddle --environment sandbox products list --include prices。通过 SDK:paddle.products.list({ include: ["prices"] })。或者请用户在控制面板中检查 Paddle > Catalog > Products。 - 确认你报告的 ID 相符。 通过 MCP:对每个新产品调用
client.products.get(productId, { include: ["prices"] })(注意productId是位置路径参数)。通过 SDK:paddle.products.get(id, { include: ["prices"] })。检查名称和税务类别。 - 建议下一步。 建议用户接下来完成
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 告知用户;由用户(或经用户批准后的你)明确提交更改。