> ## 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.

# 联盟分销

> 给推广者付佣金——两家 SaaS 任挑，或者用内置佣金跟踪器搭配任意支付网关。

联盟分销是 SaaS 增长的飞轮 —— 让客户带客户，比花钱投广告 CAC 低很多。
vibestrap 给你接好水管,几天内就能开起一套联盟计划：cookie 捕获、注册归因、
佣金计算、provider 一行切换。

挑 **internal**（零月费、数据在自己手里、适配任意支付网关包括 Creem 和
NOWPayments），或者交给 **Rewardful** / **Affonso**（托管后台,\$30-50/月,
仅支持 Stripe）。切换只改一行 config —— 不需要重写。

## 前置条件

* SaaS provider：去对应平台注册账号，拿 public API key 或 program ID。
* internal：什么都不用。`affiliate_referral` 和 `affiliate_commission` 两张表已经在 schema
  里（`src/db/affiliate.schema.ts`），`pnpm db:push` 一起迁移。
* 已经配好支付 provider（Stripe、Creem 或 NOWPayments 任一）。

## 一步步配置（internal）

1. 在 `src/config/site.ts` 启用 internal：

   ```ts theme={null}
   affiliate: {
     enable: true,
     provider: 'internal',
     internalCommissionPct: 20,    // 付款金额的百分比
     referralCookie: 'vbs_ref',    // ?ref=CODE 落地后写的 cookie 名
     referralCookieDays: 60,
   },
   ```

2. 还没建表就先**同步 schema**——联盟相关表本来就在默认 schema 里：

   ```bash theme={null}
   pnpm db:push
   ```

3. **就这样**。流程全自动：
   * 访客打开 `?ref=CODE` → middleware 写 `vbs_ref` cookie。
   * 注册 → `recordSignupReferral(userId)` 写一行到 `affiliate_referral`（`userId`
     幂等，重复调用 no-op）。
   * 付款 → 支付 webhook 调 `recordCommission()`，读出 referral，按你设定的百分比
     插一行到 `affiliate_commission`。

4. **自己做一个 payout 看板**——Vibestrap 不带。SQL 大致这样：查
   `affiliate_commission WHERE status = 'pending'` 按 `referrer_code` 分组，
   走 Stripe Connect / 转账 / 任何方式付款，再
   `UPDATE … SET status = 'paid', paid_at = now()`。

## 一步步配置（SaaS provider）

1. 在 `src/config/site.ts` 选 provider：

   ```ts theme={null}
   affiliate: { enable: true, provider: 'rewardful' },
   ```

2. 在 `.env.local` 配对应 env 变量：

   ```bash theme={null}
   NEXT_PUBLIC_AFFONSO_PROGRAM_ID=...   # Affonso
   NEXT_PUBLIC_REWARDFUL_API_KEY=...    # Rewardful
   ```

3. **在 provider 后台把支付网关接上**（Affonso / Rewardful 都走 Stripe Connect）。
   两家 SaaS provider 都只支持 Stripe，直接从 Stripe 读事件，
   Vibestrap 不为 SaaS provider 转发任何东西。

4. **重启 `pnpm dev`** 让 public env 生效。

## 怎么挑

| Provider  | 适用场景                                                                       |
| --------- | -------------------------------------------------------------------------- |
| internal  | 不想付月租，要完全控制佣金逻辑，数据要在自己 DB 里。适配任意支付 provider——用 Creem 或 NOWPayments 就只能选这个。 |
| Affonso   | 仅支持 Stripe。支持 lifetime 跟踪，月费便宜。                                            |
| Rewardful | 仅支持 Stripe。Stripe 原生最好的那个，体验最精致。要给联盟者一个托管面板的选它。                            |

## 验证生效（internal）

1. 无痕窗口访问 `https://your.app/?ref=alice`。
2. devtools → Application → Cookies，确认 `vbs_ref=alice`，过期时间 60 天。
3. 注册账号。然后查库：
   ```sql theme={null}
   SELECT * FROM affiliate_referral WHERE referrer_code = 'alice';
   ```
4. 买点东西。再查：
   ```sql theme={null}
   SELECT * FROM affiliate_commission WHERE referrer_code = 'alice';
   ```
   应该有一行，`commission_cents = amount_cents * 0.20`。

## 常见坑

1. **Safari ITP 拦 cookie**。同域 `?ref=` 落地写的 first-party cookie 没事；
   但如果你用跨域跳转（营销子域 → 应用子域），cookie 会被丢。把 referral 落地页
   保持跟注册页同 eTLD+1。
2. **退款不会自动反向佣金**。v0.1 没自动反向——要么手动插一行退款记录
   （`commission_cents` 写负值，status 设 `cancelled`），要么在 payout 查询里
   `UPDATE … SET status = 'cancelled'`。
3. **自我推荐**。当前没有限制用户用自己的 code。在乎的话在 `recordCommission`
   加一行守卫：`if (referral.userId === input.userId) return;`。
4. **从 internal 切到 SaaS provider**。SaaS provider 在自己后端记账——
   `affiliate_commission` 里的历史数据原地保留，只有新付款才会被 SaaS provider 跟踪。
5. **cookie 名冲突**。如果你的买家自己加了一些用 `vbs_*` 前缀的统计 cookie，
   把 `referralCookie` 改成你品牌专属的名字。

## 进阶扩展

vibestrap 在"水管接好,等你接水龙头"的位置停手 —— 这是有意的设计。
internal provider 给你数据,把它做成什么样的产品由你决定:

* **Payout 管理后台** —— 推广者少于 5 个时,直接 SQL 查
  `affiliate_commission` 即可；手动 SQL 烦了再做 `/admin` 页面。
* **推广者自助后台** —— 他们会先开口要,你再做。早期一个可复制的
  推荐链接就够了。
* **自动 payout** —— Stripe Connect、PayPal Mass Pay、Wise —— 等
  你每月固定要打款时再选。

API 表面不会动:`recordSignupReferral`、`recordCommission`、两张联盟表。
在它之上扩展,不是替换。

## 官方文档

* Affonso：[affonso.io/docs](https://affonso.io/docs)
* Rewardful：[help.rewardful.com](https://help.rewardful.com/)
* 内置 schema：`src/db/affiliate.schema.ts`
* 内置工具函数：`src/affiliate/track.ts`
