Skip to main content
vibestrap supports five affiliate options behind one config switch: three SaaS providers (Affonso, Rewardful, Tolt), an internal commission tracker, and none. The internal provider works with any payment provider because it reads the normalized payment events vibestrap already writes — no extra integration needed.

Prerequisites

  • For SaaS providers: an account with the provider and the public API key / program ID from their dashboard.
  • For internal: nothing. The affiliate_referral and affiliate_commission tables are already in the schema (src/db/affiliate.schema.ts) and migrate with pnpm db:push.
  • A payment provider already configured (Stripe, Paddle, Lemon Squeezy, or Creem).

Step-by-step (internal)

  1. Enable the internal provider in src/config/site.ts:
    affiliate: {
      enable: true,
      provider: 'internal',
      internalCommissionPct: 20,    // % of payment amount
      referralCookie: 'vbs_ref',    // ?ref=CODE → cookie name
      referralCookieDays: 60,
    },
    
  2. Push the schema if you haven’t already — the affiliate tables ship in the default schema:
    pnpm db:push
    
  3. That’s it. The flow is automatic:
    • A visitor lands on ?ref=CODE → middleware sets the vbs_ref cookie.
    • They sign up → recordSignupReferral(userId) writes a row to affiliate_referral (idempotent on userId).
    • They pay → the payment webhook calls recordCommission() which reads the referral and inserts an affiliate_commission row at your default %.
  4. Build a payout dashboard — vibestrap doesn’t ship one. Query affiliate_commission WHERE status = 'pending', group by referrer_code, pay out via Stripe Connect / wire / whatever, then UPDATE … SET status = 'paid', paid_at = now().

Step-by-step (SaaS providers)

  1. Pick a provider in src/config/site.ts:
    affiliate: { enable: true, provider: 'rewardful' },
    
  2. Set the matching env var in .env.local:
    NEXT_PUBLIC_AFFONSO_PROGRAM_ID=...   # for Affonso
    NEXT_PUBLIC_REWARDFUL_API_KEY=...    # for Rewardful
    NEXT_PUBLIC_TOLT_API_KEY=...         # for Tolt
    
  3. Connect the provider to your payment gateway in their dashboard (Stripe Connect for Rewardful/Tolt, Paddle integration for Affonso, etc). The provider reads payment events directly from the gateway — vibestrap doesn’t relay anything for SaaS providers.
  4. Restart pnpm dev to pick up the public env var.

Pick the right provider

ProviderWhen to pick
internalYou want zero ongoing fees, full control over commission logic, and your data in your DB. Ships with Creem/Lemon out of the box.
AffonsoSolid Stripe + Paddle integration, lifetime tracking, low monthly cost.
RewardfulMost polished Stripe-native option. Pick if you want a managed dashboard for your affiliates.
ToltSaaS-focused, leaderboards, recurring commissions. Good Stripe + LemonSqueezy support.

Verify it works (internal)

  1. Open the site at https://your.app/?ref=alice in incognito.
  2. In devtools → Application → Cookies, confirm vbs_ref=alice, expires in 60 days.
  3. Sign up. In your DB:
    SELECT * FROM affiliate_referral WHERE referrer_code = 'alice';
    
  4. Buy something. Then:
    SELECT * FROM affiliate_commission WHERE referrer_code = 'alice';
    
    You should see one row with commission_cents = amount_cents * 0.20.

Common pitfalls

  1. Safari ITP blocks cookies. First-party cookies set by your own server on a ?ref= landing are fine, but if you use cross-domain redirects (e.g. landing on a marketing subdomain → app subdomain) the cookie will be dropped. Keep the referral landing on the same eTLD+1 as the signup.
  2. Refunds don’t reverse commissions. v0.1 doesn’t auto-reverse — you need to manually insert a refund row (negative commission_cents, status cancelled) or UPDATE … SET status = 'cancelled' in your payout query.
  3. Self-referrals. Nothing blocks a user from setting their own code as the referrer. Add a guard in recordCommission if this matters: if (referral.userId === input.userId) return;.
  4. Switching from internal to a SaaS provider. The SaaS providers track on their own backend — historical commissions in affiliate_commission stay where they are; only new payments will be tracked by the SaaS provider.
  5. Cookie name collision. If your buyers add their own analytics that also uses vbs_* prefixed cookies, change referralCookie to something unique to your brand.

Official docs