core-affiliates
Referral tracking, marketing attribution, and affiliate partner management with commissions.
core-affiliates
Primitive Paid
core-affiliates provides referral tracking, first-touch marketing attribution, and affiliate partner management. Users can register as affiliates, earn commissions on conversions, and admins can analyze acquisition channels.
⚠️ Warning
This is a paid module. Adding it requires a valid Indigo license.
What it does
- Affiliate partners — users register, get a unique referral code, and earn a commission percentage.
- Referral tracking — captures the affiliate → referred-user relationship and records conversions.
- Marketing attribution — first-touch capture of UTM parameters, referrer, ref code, and landing page per user.
- Admin analytics — affiliate leaderboards, conversion rates, and attribution breakdowns by channel.
- Ships an
AttributionCapturecomponent and anAffiliateOverviewwidget.
Installation
bun run indigo add core-affiliates
After installing, generate and apply the schema:
bun run db:generate
bun run db:migrate
Configuration
Dependencies are wired through setAffiliatesDeps() in config/deps/affiliates-deps.ts:
paymentTransactionsTable— a Drizzle table reference fromcore-payments, used to compute revenue breakdowns. Passnullif billing is not installed.getRevenueByUsers— reserved for future use.
The deps file also registers two module hooks:
import { registerHook } from '@/core/lib/module/module-hooks';
import { recordConversion } from '@/core-affiliates/lib/affiliates';
import { captureAttribution } from '@/core-affiliates/lib/attribution';
registerHook('payment.conversion', (userId, referenceId, amountCents) =>
recordConversion(userId, referenceId, amountCents),
);
registerHook('attribution.capture', (userId, data) =>
captureAttribution(userId, data),
);
ℹ️ Info
core-affiliates has an optional dependency on core-payments — revenue figures in attribution breakdowns appear only when the payment transactions table is injected.
Schema
| Table | Notable columns |
|---|---|
saas_affiliates |
userId (unique), code (unique referral code), commissionPercent (default 20), status (active/suspended/banned), totalReferrals, totalEarningsCents |
saas_referrals |
affiliateId, referredUserId (unique), referredOrgId, status (pending/converted), convertedAt |
saas_affiliate_events |
affiliateId, referralId, type, amountCents, metadata — affiliate activity log |
saas_user_acquisitions |
userId (unique), refCode, utmSource, utmMedium, utmCampaign, extra (JSONB — utm_term/content, referrer, landing page), capturedAt |
API
affiliatesRouter (mounted as affiliates):
| Endpoint | Access | Purpose |
|---|---|---|
affiliates.getMyAffiliate |
protected | Get the current user's affiliate record |
affiliates.register |
protected | Register the current user as an affiliate |
affiliates.getStats |
protected | The user's own referral stats and recent events |
affiliates.adminList |
admin (billing) |
List all affiliates with filters |
affiliates.adminGet |
admin (billing) |
Affiliate detail with referrals and events |
affiliates.updateStatus |
admin (billing) |
Change an affiliate's status |
affiliates.updateCommission |
admin (billing) |
Change an affiliate's commission percentage |
affiliates.getAffiliateStats |
admin (billing) |
Dashboard stats and the top-affiliates leaderboard |
attributionsRouter (mounted as attributions):
| Endpoint | Access | Purpose |
|---|---|---|
attributions.distinctValues |
admin (billing) |
Distinct sources/mediums/campaigns/ref codes for filters |
attributions.breakdown |
admin (billing) |
Signups (and revenue, if billing installed) grouped by a dimension |
attributions.list |
admin (billing) |
Paginated attribution list with filters |
Integration
- Call
captureAttribution()from your auth/registration flow to record first-touch attribution, andrecordConversion()from payment webhooks — or trigger them via theattribution.captureandpayment.conversionhooks. captureReferral()records a referral after registration (active affiliates only, self-referrals blocked).- Render the
AttributionCapturelayout widget in your public layout to capture UTM parameters on landing. - The
AffiliateOverviewpage widget renders in thebillingslot; a nav itemAffiliatesis registered under thebillinggroup. - The seed
seedAffiliatescreates demo referrals and commissions.