Skip to content

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.
  • SortCREATED_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

  1. Onboard a new affiliate. Partnerships creates an affiliate from an existing user via POST /admin/affiliate. Backend writes Affiliate row, attaches default level. Issue a code via POST /admin/affiliate/code with vanity slug. Tell affiliate to promote https://dropbet.com/?ref=SLUG.
  2. Review monthly payouts. Finance opens /affiliates, sorts by REVENUE_USD DESC. Drills into top 20, opens stats tab — referrals, FTDs, NGR, owed commission. Cross-checks against withdrawals.md for payout records.
  3. 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.
  4. 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).
  5. 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/users returns paginated affiliate records. POST /admin/affiliate/find-one-extended returns 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 EBIT100 and ebit100 collide. The DB has a unique index on LOWER(slug).
  • Soft-delete preserves attribution. Deleting a code does not retroactively un-attribute referrals — referrals stay tied via Referral.codeId.
  • AffiliateLevel is 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 Affiliate subtype. Some queries filter by Affiliate.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.
  • 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.mdGET /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