Skip to main content
Affiliate programs are a growth flywheel — your customers bring you more customers, often at a fraction of paid-ad CAC. vibestrap ships the plumbing so you can run one in days instead of weeks: cookie capture, signup attribution, commission calculation, and a one-line provider switch. Pick internal (zero monthly fee, your data, works with any payment gateway including Creem and NOWPayments) or hand off to Rewardful / Affonso (managed dashboards, ~$30-50/mo, Stripe-only). Switching is one config line — never a rewrite.

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, Creem, or NOWPayments).

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
    
  3. Connect the provider to your payment gateway in their dashboard (Stripe Connect for Affonso/Rewardful). Both SaaS providers are Stripe-only — they read payment events directly from Stripe and Vibestrap doesn’t relay anything for them.
  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. Works with any payment provider — pick this if you’re on Creem or NOWPayments.
AffonsoStripe-only. Lifetime tracking, low monthly cost.
RewardfulStripe-only. Most polished Stripe-native option. Pick if you want a managed dashboard for your affiliates.

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.

Going beyond

vibestrap stops at “wires connected, ready to extend” — by design. The internal provider gives you data; how you turn it into a product is yours to shape:
  • Payout admin UI — query affiliate_commission directly while you have under five affiliates; build a /admin page when manual SQL hurts.
  • Affiliate self-service dashboard — they ask for it before you need to build it. A copy-able referral link is enough at first.
  • Auto payouts — Stripe Connect, PayPal Mass Pay, Wise — pick when you have a monthly-or-tighter cadence.
The API surface won’t move under you: recordSignupReferral, recordCommission, and the two affiliate tables. Build on top — don’t rewrite.

Official docs