Affiliates¶
Purpose¶
The Affiliates screen manages the affiliate / referral program: levels (commission tiers), affiliate users (the operators of referral codes), individual affiliate codes, and referral attribution. It is a mid-frequency screen — checked daily by partnerships, weekly by finance for payout reconciliation.
Audience¶
Partnerships team (primary), finance (payout review), risk (attribution-fraud).
Path in admin-fe¶
| Screen | URL | Page |
|---|---|---|
| Affiliates list | /affiliates |
ebit-admin-fe/src/app/(dashboard)/affiliates/page.tsx |
| Affiliate drill-in | /affiliates/[id] |
ebit-admin-fe/src/app/(dashboard)/affiliates/[id]/page.tsx |
Affiliates accordion in the sidebar also exposes streamers.md — streamers are a specialized affiliate sub-type.
Backing API endpoints¶
| Endpoint | Source |
|---|---|
POST /admin/affiliate (create) |
apps/api/src/affiliate/admin.affiliate.controller.ts:29 |
GET /admin/affiliate/levels |
apps/api/src/affiliate/admin.affiliate.controller.ts:40 |
POST /admin/affiliate/users (paginated find) |
apps/api/src/affiliate/admin.affiliate.controller.ts:50 |
POST /admin/affiliate/find-one |
apps/api/src/affiliate/admin.affiliate.controller.ts:61 |
POST /admin/affiliate/find-one-extended |
apps/api/src/affiliate/admin.affiliate.controller.ts:70 |
POST /admin/affiliate/find-one-stats |
apps/api/src/affiliate/admin.affiliate.controller.ts:79 |
POST /admin/affiliate/code (create) |
apps/api/src/affiliate/code/admin-affiliate-code.controller.ts:27 |
DELETE /admin/affiliate/code |
apps/api/src/affiliate/code/admin-affiliate-code.controller.ts:18 |
Frontend wiring: ebit-admin-fe/src/queries/affiliate/.
Key actions¶
| Action | Required permission | API call | DB tables touched | Audit-logged? |
|---|---|---|---|---|
| List affiliate users | affiliate.users.view |
POST /admin/affiliate/users |
Affiliate, User |
yes |
| View one affiliate | affiliate.find-one.view |
POST /admin/affiliate/find-one |
Affiliate, AffiliateCode, User |
yes |
| View affiliate stats | affiliate.find-one-stats.view |
POST /admin/affiliate/find-one-stats |
Affiliate, aggregated Bet, Deposit |
yes |
| Create affiliate (promote a user) | affiliate.view (write) |
POST /admin/affiliate |
Affiliate, User |
yes |
| List levels (commission tiers) | affiliate.levels.view |
GET /admin/affiliate/levels |
AffiliateLevel |
yes |
| Create affiliate code | affiliate-code.create |
POST /admin/affiliate/code |
AffiliateCode |
yes |
| Delete affiliate code | affiliate-code.delete |
DELETE /admin/affiliate/code |
AffiliateCode (soft-delete) |
yes |
Filters and views¶
- Search — by user email, twitch handle, code.
- Sort —
CREATED_AT,REVENUE_USD,REFERRAL_COUNT. - Level filter — bronze / silver / gold / etc. (level catalog comes from
GET /admin/affiliate/levels). - Date range — affects stats only.
- Drill-in tabs on
/affiliates/[id]: Overview, Codes, Referrals, Stats, Payouts.
Common workflows¶
- Onboard a new affiliate. Partnerships creates an affiliate from an existing user via
POST /admin/affiliate. Backend writesAffiliaterow, attaches default level. Issue a code viaPOST /admin/affiliate/codewith vanity slug. Tell affiliate to promotehttps://dropbet.com/?ref=SLUG. - Review monthly payouts. Finance opens
/affiliates, sorts byREVENUE_USD DESC. Drills into top 20, opens stats tab — referrals, FTDs, NGR, owed commission. Cross-checks against withdrawals.md for payout records. - Investigate attribution fraud. Risk gets a tip that an affiliate is self-referring. Open the affiliate, check Referrals tab — if all referred users registered from the same IP / device fingerprint (visible on
/admin/registration-info/:userId), that's a smoking gun. Disable the code, ban the affiliate, refund the platform via user-profile.md → admin-tip negative deduct. - Promote affiliate to higher tier. Open the affiliate detail, edit level. Backend updates
Affiliate.levelId. Commissions for new bets pick up the new tier; in-flight payouts retain old tier (audit clarity). - Decommission a code. Click Delete on the code row. Backend soft-deletes (
deletedAt). New visitors via the link get redirected to a generic landing; existing referrals stay attributed.
Edge cases / gotchas¶
- The "users" endpoint and the "find-one-extended" endpoint diverge.
POST /admin/affiliate/usersreturns paginated affiliate records.POST /admin/affiliate/find-one-extendedreturns one record with joined recent bets / deposits / referral chain. Don't paginate the latter. - Codes are case-insensitive on lookup but case-sensitive on create. A code
EBIT100andebit100collide. The DB has a unique index onLOWER(slug). - Soft-delete preserves attribution. Deleting a code does not retroactively un-attribute referrals — referrals stay tied via
Referral.codeId. AffiliateLevelis platform-wide. No per-affiliate custom levels — if a partner needs a special deal, you create a new level and assign it.- Streamer is an
Affiliatesubtype. Some queries filter byAffiliate.streamerProfile IS NOT NULL. See streamers.md. - No bulk import. Single-creation only via UI. Bulk onboarding requires a one-off script.
- The "Stats" tab caches aggregates — turnover, NGR, revenue. There is a 5-minute lag.
- Payout history is not on this screen. Payouts ride the withdrawals.md flow keyed on
Withdraw.affiliateId.
Cross-links¶
- Streamers (subtype of affiliate): streamers.md
- Per-user view of affiliate code on a player: user-profile.md → Referral tab
- Player-side referral code endpoint:
apps/api/src/affiliate/code/affiliate-code.controller.ts - Payout reconciliation: withdrawals.md, dashboard.md → finance tab
- Affiliate dashboard tile: dashboard.md →
GET /admin/dashboard/affiliate-stats - Audit feed: admin-logs.md
Sequence — creating an affiliate code¶
sequenceDiagram
actor admin
participant admin-fe
participant api
participant pg as Postgres
admin->>admin-fe: open /affiliates/[id], click "Create code", slug="EBIT100"
admin-fe->>api: POST /admin/affiliate/code { affiliateId, slug, commissionOverride? }
api->>api: PermissionGuard('affiliate-code.create')
api->>pg: INSERT AffiliateCode (slug=lower("EBIT100"), affiliateId, ...)
pg-->>api: created
api->>pg: INSERT AdminActionLog
api-->>admin-fe: AffiliateCode DTO
admin-fe-->>admin: code added to list, share URL exposed