跳到正文

SaaS 订阅与支付 API ​

SaaS 订阅与支付 API 提供套餐查询、付款创建和订阅管理等接口。使用平台现成页面的接入方式,请参见第三方 SaaS 订阅与支付。

调用前,请确认当前应用已开通对应 API 产品,并使用指定环境和版本。Production 尚未开放,产品登记不会自动开通正式环境。

1. 准备调用权限 ​

在开发者控制台中为当前应用配置所需的 API 权限,然后使用客户用户的身份调用接口。客户还需要有效的企业成员关系、商业资料和付款资格。

每次请求携带以下请求头:

text
Authorization: Bearer ${GOODVISION_USER_ACCESS_TOKEN}
X-GV-Organization-ID: ${GOODVISION_CUSTOMER_ORGANIZATION_ID}
X-GV-Application-ID: ${GOODVISION_APPLICATION_ID}
Endpoint最小 Scope
GET /open-platform/v1/productscommerce.catalog.read
POST /open-platform/v1/checkout-sessionscommerce.checkout.create
POST /open-platform/v1/free-activationscommerce.checkout.create
GET /open-platform/v1/operations/{id}commerce.checkout.read
GET /open-platform/v1/subscriptionscommerce.subscription.read
GET /open-platform/v1/subscriptions/{id}commerce.subscription.read
POST /open-platform/v1/subscriptions/{id}:cancelcommerce.subscription.manage
POST /open-platform/v1/subscriptions/{id}:change-plancommerce.subscription.manage
POST /open-platform/v1/subscriptions/{id}:change-pricingcommerce.subscription.manage
GET /open-platform/v1/customer-quotes/{id}commerce.catalog.read
GET /open-platform/v1/customer-quotescommerce.catalog.read
POST /open-platform/v1/customer-quotes/{id}/acceptcommerce.checkout.create
POST /open-platform/v1/customer-quotes/{id}/declinecommerce.checkout.create

2. 查询套餐并创建付款 ​

匿名读取公开套餐 ​

GET /open-platform/v1/public/pricing无需登录或申请调用权限。必须同时提供application、environment和product查询参数,返回该范围正式公开发布的方案、价格、条款、Credits、席位、FAQ及purchase_availability。客户专属方案不返回;首月优惠eligibility为unverified,没有selection_revision。购买状态为not_enabled或suspended时可看价格但不可下单。参数非法返回422、没有公开目录返回404、来源无法核验返回503,不使用其他应用或旧价格兜底。这个只读接口不接受客户组织,不能替代登录、条款确认或创建Checkout。

environment=sandbox 展示显式公开的当前测试套餐,不要求 Production 上线审批;暂停、撤回和客户专属可见范围继续生效。Production 始终读取已批准并显式发布的版本。登录后的测试购买使用 GET /open-platform/v1/application-listings?application_id=<application-id>&environment=sandbox 核验单一测试应用;不带参数的应用市场列表仅包含正式发布应用。

查询机会关联的报价 ​

卖方可使用 GET /open-platform/v1/appmarket/quotes?opportunity_id=<机会ID>&limit=20 查询某个机会的报价,需要 operations.opportunity.read 权限。

  • 查询包含该机会的全部报价状态,可同时使用 search 和 status 筛选。
  • 读取下一页时保留原筛选,并原样传回 next_cursor。更换机会或筛选后,从第一页重新查询。
  • 返回 404 表示当前范围内没有该机会。展示报价前,再次 GET 报价详情并核对来源和当前状态。

平台机会详情中的报价区块用于查看。修改报价请使用正式报价页面或已授权的报价 API。客户接受报价后,仍需另行创建订单和付款。

查看客户收到的报价 ​

客户可在客户工作区的「应用订阅与账单 → 收到的报价」查看和处理报价,使用当前登录身份及所选应用。

自建客户页面使用 GET /open-platform/v1/customer-quotes?limit=10 查询当前客户企业与应用的报价,每页最多 10 条。下一页原样传回 next_cursor。查询失败时显示错误并提供重试;切换企业或应用时,清除旧游标和未提交的确认内容。

使用 GET /open-platform/v1/customer-quotes/{id} 获取已发送报价。客户需要与当前应用存在有效的商业关系;尚未发送的新修订无法读取。

接受或拒绝报价时,提交当前报价的 resource_version、revision、原样的 terms_sha256 和原因,并携带原 Idempotency-Key。请让客户本人确认所收到的版本,卖方不能代为决定。

提交接受时,平台会重新检查报价来源和有效期。方案停售或条款变化会返回 409;请重新读取并让客户确认。已发送且未到期的报价,即使方案停售,客户仍可拒绝。报价撤回、修订、到期或已有决定后,不能再提交新决定。

结果不明时恢复原请求,再 GET 当前报价。接受或拒绝只保存客户决定,订单、付款、订阅和产品开通需分别办理。

sh
curl --request GET \
  --url "${GOODVISION_API_BASE}/open-platform/v1/products" \
  --header "Authorization: Bearer ${GOODVISION_USER_ACCESS_TOKEN}" \
  --header "X-GV-Organization-ID: ${GOODVISION_CUSTOMER_ORGANIZATION_ID}" \
  --header "X-GV-Application-ID: ${GOODVISION_APPLICATION_ID}"

响应包含当前 product 和 plans。将返回的套餐、价格和条款展示给客户确认,成交金额由平台计算。

创建付款时,使用固定的 Idempotency-Key,并提交所选目录的版本和客户确认内容:

json
{
  "plan_code": "<catalog plan code>",
  "plan_version": 3,
  "billing_interval": "month",
  "sales_offer_ref": "<catalog offer reference>",
  "sales_offer_version": 2,
  "selection_revision": "<catalog selection revision>",
  "accepted_terms_sha256": "<accepted terms SHA256>"
}

请求参数要求如下:

参数必填性说明
Idempotency-Key🔴 必填Header,恢复原请求时保持不变
plan_code、plan_version🔴 必填使用所选目录返回的值
billing_interval🔴 必填month 或 year
selection_revision、accepted_terms_sha256🔴 条件必填所选目录返回时必填;原样使用目录版本和客户确认的条款摘要
sales_offer_ref、sales_offer_version🔴 条件必填成组使用目录返回值;仅当前接口配置允许时可同时省略
seat_quantity🔴 条件必填seat_pricing 套餐必填且在席位上下限内;固定价方案不传
return_reference可选已配置的回跳引用;不指定应用回跳时可省略

请求不接受任意回跳 URL、金额、币种或支付供应商。

应用内付款可使用return_reference: "application-entry",成功与取消均返回当前应用已审核发布的访问地址。请先在应用发布信息中配置正确的 HTTPS 地址;地址和应用环境必须匹配。平台在原购买中保存地址,后续修改发布信息不会改变原付款返回地址。普通平台工作区可继续使用其已配置的回跳引用。

返回参数payment、payment_order、organization、application、environment、product及订阅的payment_subscription只用于选择当前已授权原操作。payment=success不表示付款或开通已确认。先回读原操作;事件尚未到达时可有时限地自动查询,失败或超时保留手动恢复,不再次购买。

目录包含 seat_pricing 时,价格、基础月度 Credits 和活动月度 Credits 均按每席位计。购买时显式提交 seat_quantity,且在 minimum_seats 与 maximum_seats 范围内。确认页可展示预估总价,订单总价以平台核验结果为准。固定价方案不提交席位乘数。

结果不明时,使用原正文、人数和请求键恢复。恢复原订单时保持原人数。

配置套餐请打开当前应用的「交易 → 订阅套餐」,选择已准备的产品和服务商创建草稿,也可基于已有方案创建。草稿支持月/年价、Credits、席位范围或固定总容量、条款、推荐和 FAQ。新价格和方案分别通过审核,并更新应用发布信息后,客户才可购买。保存草稿不会改变历史订单。

收到 202 后,按以下步骤继续:

  1. 保存 operation_id、resource_version 和短期有效的 checkout_url。
  2. 跳转到 checkout_url 完成付款。
  3. 使用 GET /open-platform/v1/operations/{id} 查询原操作的 status、next_step 和当前版本。

202 仅表示已受理。客户回跳后,请查询付款和订阅状态,再展示完成结果。

3. 查询、取消与变更订阅 ​

激活免费套餐 ​

零价月套餐使用 POST /open-platform/v1/free-activations。提交与新套餐选择相同的正文,省略 return_reference,保留目录版本、选择指纹和已接受条款。

成功返回 201,响应包含 order_id、subscription_id、status 和 resource_version。免费激活无需支付方式,也不返回付款会话。重复请求使用原正文和原键。零价年套餐暂不支持;零金额请求不能提交到付费 Checkout。

免费订阅返回 billing_mode: free。月度 Credits 按原接受周期发放,未使用部分在周期结束时到期。选择周期末取消后,可继续使用到返回的截止时间。

升级免费订阅 ​

先读取当前免费订阅,再在新付费 Checkout 正文中同时提交 upgrade_from_subscription_id 和 upgrade_from_subscription_version。来源发生变化会返回 409,此时重新读取并让客户确认;结果不明时,保持原来源、版本、正文和请求键恢复。

付款成功前,原免费套餐继续有效,新付费订阅为 pending_payment。恢复付款时选择新付费订阅及原操作。取消付款会保留免费服务;平台确认付款成功后,启用付费套餐并停止原免费套餐的剩余 Credits。

分别查询订阅、付款、额度和产品开通状态。回跳只表示客户返回页面。

查询订阅 ​

订阅列表返回 items,详情返回当前客户与应用范围内的订阅信息。保存订阅 ID 和 resource_version。商业订阅 ID 与 API 调用授权 ID 分别使用。

取消或变更套餐 ​

发送原操作的 Idempotency-Key,并使用刚查询到的版本设置 If-Match: "<resource_version>"。

  • 取消:提交 {"cancel_mode":"end_of_period","reason":"客户停止续费"}。使用 immediate 则立即取消。
  • 变更:提交 {"new_plan_code":"<catalog plan code>","new_plan_version":3}。可选的 effective_at 和 reason 按当前接口要求填写。

价格由平台确定。取消订阅后,退款需另行办理。

两项操作返回 202 时,表示请求已受理。重新查询原订阅,并使用已订阅的生命周期事件更新状态。到期时间、生效时间和使用权限以当前响应及 SaaS 账务契约为准。

4. 错误与恢复 ​

状态码或情况处理方式
401/403检查当前用户、企业、应用、Scope 和客户操作资格
409重新读取版本、目录和条款,让客户确认变化后的条件
400/422按接口说明修正请求参数
503 或响应丢失先查询原操作或订阅,再用原正文和原请求键恢复

付款结果不明时,保留原操作和原键,避免创建第二笔付款。恢复请求保持原确认条款。

产品、付款、商业订阅和使用权益是独立状态。更多示例见可复制接入模板与幂等与重试。

5. 配置订阅套餐和 Credits ​

开启免费激活 ​

free_activation_enabled 控制当前应用、产品和环境下的新免费激活,首次默认关闭。

配置行为
复制方案时省略字段继承原配置
显式 false关闭新免费激活
null请求被拒绝

仅零价月方案可以开启,经审核和发布后进入客户可售目录。关闭免费激活后,已有订阅、原订单恢复和成交额度继续保留。

欢迎、每日活跃和活动赠额分别配置,数量为 0 时关闭对应赠额。付费项目也可配置这些赠额。

在开发者控制台的当前应用中打开「交易 → 订阅套餐」,选择已有商品来源后新建草稿。可设置独立USD月价/年价、套餐分组、推荐项、总成员容量、纯文本成交条款及FAQ顺序。独立价格和套餐需要审核及发布后才可销售,来源方案和历史订单不会被覆盖。首次商品来源需先完成商业接入准备。

配置 Credits ​

Credits 规则指定每月额度、活动期和每 Credit 对应的加权消费单位。年付套餐也按月发放额度,各月额度在对应周期结束时到期。加量包使用其购买时确定的金额、模型倍率和有效期。

订阅与加量包的范围和换算比例一致时,可共同显示 Credits 余额,同时保留原始 Token 用量和加权扣减。历史额度未声明换算比例,或混用比例时,继续显示原加权单位;浏览器不能自行改名或合并不同产品的余额。

配置首月优惠 ​

首月优惠默认关闭。在套餐草稿中设置 introductory_pricing: {"first_month_amount_scaled":700},可将首月价格设为 7 美元。正常月费由独立价格定义,例如 10 美元。

仅固定价、付费、USD 月套餐支持首月优惠。首价必须大于 0 且低于正常价;年付、免费和按席位套餐暂不支持。复制时省略字段会继承优惠,显式 null 则关闭新草稿优惠。已有订单保留购买时的条件。

客户目录的 first_month_offer 返回优惠金额和当前 eligibility。按以下状态展示:

状态展示与处理
eligible展示首月优惠价
not_eligible、unverified展示正常价
pending展示正常价,并提示用户在原工作区恢复待完成的优惠付款

当前应用、实际产品和环境内,每位核验用户仅可使用一次优惠。既往试用或付款会排除资格;取消、重订和退款不会恢复资格。

购买确认页分别展示首月金额和第二个月起的正常月费,并回传原 selection_revision。金额与优惠资格由平台核验。资格变化返回 409 时,重新读取目录并确认。

付款失败或结果不明时,保留原订单和请求键。仅平台确认付款已终态取消后,才释放未完成的优惠。原订单中的 recurring_amount_scaled 是购买时确定的第二个月起月费,请直接展示该值。

套餐配置还需满足以下条件:

  • 免费档仅支持月周期,月价可为 0。总成员容量与按席位定价不能同时配置。
  • 欢迎和每日活跃赠额需要已接入相应的资格校验与发放能力,配置策略字段不会直接发放额度。
  • 全额退款可停止订阅剩余额度。自动续费取消、完整退款和使用权限政策,以当前接入配置及说明为准。

提交结果不明时使用原请求恢复,核对价格、容量、条款和FAQ回执后再更新界面;切换应用或环境清除未提交内容。客户目录、购买及取消继续使用前述用户权限和当前允许动作,开发者管理关系不等于客户付款资格。

个人版、企业版与 SaaSdemo 演示 ​

控制台提供五个可编辑参考模板:

模板收费每月基础 Credits成员
Free$0/月1001
Pro 月付首月 $7,之后 $10/月10001
Pro 年付$96/年,月均 $810001
Team 月付$40/席位/月1000/席位可选2–100席;限时赠额另行配置
Team 年付$480/席位/年1000/席位可选2–100席;限时赠额另行配置

模板会填入新草稿,保存、审核和发布需分别完成。可删除免费档,或调整名称、价格、席位和额度。仅 SaaSdemo 应用的首次新建表单默认选中 Free;其他应用默认关闭免费运营。

保存前,请填写实际可用的模型及倍率。缺少模型引用时需补齐,示例模型不能替代真实授权。欢迎、日活和活动赠额默认关闭,须按已接入的发放能力分别配置。年付按月发放 Credits;企业额度与付款金额按购买席位数计算。

准备演示目录时:

  1. 在商业来源旁选择「准备套餐组」。SaaSdemo 默认包含 Free,其他应用默认包含四档付费套餐;可调整「套餐组包含 Free 演示」。
  2. 逐档检查价格、额度、成员容量、条款和 FAQ,并按需要修改。
  3. 点击「保存当前套餐并继续」。已核对的模型及倍率会带入下一档,各档赠额策略分别配置。

每档使用独立请求和幂等键。结果不明或返回内容与请求不一致时,当前档会锁定;先通过「重试原请求」恢复,确认后再提交下一档。

「跳过当前档」不创建资源;「稍后继续配置」保留已保存套餐,未保存表单不会持久化。重新准备时,仅复用当前目录中编号、产品和服务商完全匹配的方案。重名或商业来源不一致时,请先核对;自定义编号的方案在目录中单独处理。

完成后按「审批与发布清单」分别审批价格及方案并发布,再在「应用发布信息」选择当前产品与环境下已发布的方案及版本。客户页面只读取已发布目录。成套准备不会自动审批、发布或开通客户。切换模板会清除不适用的首月、固定容量或按席位策略;已有客户订单和订阅保持原成交规则。

先发布套餐,稍后配置访问地址 ​

在「应用发布」勾选当前应用与环境内已批准并发布的套餐。若暂未准备产品访问地址,可明确清空地址并保存;至少选择一个有效套餐。保存后公开价目可读,不代表订阅支付或产品已经开通。非空地址仍须满足 HTTPS 发布校验。后续补正确产品地址,再核验实际产品进入;没有地址的发布不能用作导流或自行收费资源。订阅购买未启用或暂停时仍显示价格,并说明当前不可购买。

独立定价页与 URL 参数 ​

从已签发接入配置的platform.consoleOrigin构造独立页面:

ts
const url = new URL('/console/pricing', configuration.platform.consoleOrigin);
url.searchParams.set('application', configuration.application.slug);
url.searchParams.set('environment', configuration.application.environment);
url.searchParams.set('locale', 'zh-CN');
// 匿名定价页必须明确已配置的产品代码。
url.searchParams.set('product', configuredProductCode);

application是应用slug;environment为sandbox或production;匿名查看时product为必需产品代码;locale支持zh-CN、en-US。SaaSdemo自身的/pricing展示同一托管内容,参数必须匹配该实例的应用绑定。独立页无工作区侧栏,保留个人/企业、月/年切换、套餐比较、FAQ和订阅管理入口;年付选择保留Free月度方案。

独立定价页无需登录,按这三个范围展示正式公开发布的套餐,客户专属报价不会公开。查看价格不会创建企业、订单或订阅。点击购买或「我的订阅」后才进入登录,保留应用、环境、产品及已选套餐;购买确认重新核验当前资格和完整条款,不自动提交。首月优惠在匿名页面说明适用条件,登录后核验资格。参数不是认证凭据,无权或错误参数不能回退到另一应用。iframe延续embed=1&view=subscription&auth=parent-bff协议,主题与语言跟随宿主,内容高度自动调整。客户付款金额、优惠资格和最终权益仍由当前目录及购买确认决定,不从URL接受金额或权限。

这一入口适用于所有已完成商业接入并发布套餐的开放平台应用,平台不按应用名称限制。SaaSdemo的定价使用iframe,页脚提供「单独打开定价页」;两者保留同一application/environment/product。定价页不混入当前订阅和支付方式;登录后的「我的订阅」通过弹窗管理,完整管理页为/console/subscription,同样保留选择范围。免费运营由每个应用显式配置并发布,没有免费方案的应用不显示Free。

同一SaaSdemo构建可用于不同应用实例;实例的应用和环境来自已签发配置,不能由访客参数改写。订阅、账单和定价之间跳转继续保留所选产品。错误或重复选择参数会停止加载,订阅管理入口也不可用。独立平台定价页可查看其他应用正式发布的公开套餐;购买时核验当前用户授权。

嵌入时复用独立URL,添加展示和宿主认证协议参数,继续使用当前应用的同源桥接:

ts
const embedded = new URL(url);
embedded.searchParams.set('embed', '1');
embedded.searchParams.set('view', 'subscription');
embedded.searchParams.set('auth', 'parent-bff');
iframe.src = embedded.toString();
standaloneLink.href = url.toString();
standaloneLink.target = '_blank';
standaloneLink.rel = 'noreferrer';

auth=parent-bff要求接入方完成宿主认证桥接,继续使用当前应用登录会话和允许的订阅操作;仅设置iframe的src不会建立登录或商业关系。宿主必须校验消息的精确来源、当前iframe窗口和字段,并在服务端核验会话、CSRF及当前权限。凭据不能进入URL或跨窗口消息。新客户尚未准备付款主体和商业资料时,需要先完成商业准备;已有其他客户的成功订阅不能替代该关系。

配置一次性Credits加量包 ​

在当前Application打开「交易 → Credits 加量包」,选择可用模型产品,准备独立USD价格与加量包草稿。参考配置为500 Credits、15美元、1个自然月、不退款,可按产品运营策略调整。可设置Credits换算、模型及倍率、天数或自然月、适用订阅代码、条款和退款;独立购买无需订阅条件。免费订阅资格必须另行显式允许,不会自动开启免费套餐运营。

价格和加量包会一起保存为草稿。先审核价格,再单独审核并发布加量包,客户才可购买。草稿不会创建客户订单或发放额度,历史订单保留购买时的版本。

结果不明,或返回的价格、期限、资格、退款政策与请求不一致时,表单保留并锁定原内容和键。请恢复同一请求。切换企业、应用、环境或权限后,清除临时状态。

客户购买资格、订单恢复和到期规则请参见 Token API 指南。查询付款状态后,还需单独核对额度是否到账。

开发者文档。第三方接入不需要内部运营平台权限。