> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vibestrap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 支付概览

> 默认用一条 Stripe checkout 跑通，Provider 切换作为高级能力保留。

Vibestrap 的支付系统优先服务模板使用者：配置产品，传一个 `productId`，
模板负责 checkout、webhook、订单入库、积分发放、license 签发和账单门户。

## 最快路径

大多数项目只需要改三个地方：

1. 在 Stripe 创建 Products + Prices。
2. 把 price ID 填进 `.env.local`。
3. 在 `src/config/site.ts` 调整套餐和积分包。

调用 checkout 时保持很小：

```ts theme={null}
await createCheckoutAction({ productId: 'pro' });
await createCheckoutAction({ productId: 'credits_standard' });
```

未登录也能点的购买链接使用：

```txt theme={null}
/checkout?productId=pro
```

未登录用户会先去登录，登录后回到 `/checkout`，自动进入托管收银台。

## 配置层次

`siteConfig.billing` 是新手最先看的配置：

```ts theme={null}
billing: {
  enabled: true,
  defaultProductId: 'pro',
  successPath: '/settings/billing?status=success',
  cancelPath: '/pricing?status=canceled',
}
```

`siteConfig.demoPlans` 定义示例 SaaS 的 4 档套餐。
`siteConfig.payment` 是高级 Provider 层：默认启用 Stripe；需要备用通道时
再打开 Creem 或 NOWPayments。

## Provider 门面

Provider 代码仍然在同一个契约后面：

```ts theme={null}
interface PaymentProvider {
  createCheckout(opts): Promise<{ id: string; url: string }>;
  createPortalLink(opts): Promise<{ url: string }>;
}
```

Stripe、Creem、NOWPayments 的 webhook 都会被归一化成同一种
`NormalizedEvent`。`src/payment/handlers/core.ts` 里的共享 handler 负责写
`payment`、发积分、签 license、记录 affiliate commission。

## 幂等

Provider 重试 webhook 是常态。`payment` 表对 `invoiceId` 和 `sessionId`
都有唯一索引；handler 用 conflict protection 插入订单，再按 `paymentId`
幂等发放权益。

所以同一个 webhook 重放，不应该产生重复订单、重复积分、重复 license 或重复佣金。

## Provider 选择

| Provider    | 适合         | 备注                    |
| ----------- | ---------- | --------------------- |
| Stripe      | 默认 SaaS 收款 | 订阅、一次性、积分包、账单门户。      |
| Creem       | 备用卡支付/本地通道 | 当 Stripe 不适合你的市场时再启用。 |
| NOWPayments | 加密货币一次性付款  | 不支持订阅，只适合 invoice 流程。 |

## 验证

1. 在 `.env.local` 配好 Stripe key 和 price ID。
2. 运行 `pnpm dev`。
3. 打开 `/checkout?productId=pro`。
4. 完成测试支付。
5. 确认 `payment` 表出现记录，并且积分/license 正确发放。
6. 重放 webhook；数据库不应该新增重复数据。
