Rewards System
Points engine, mission system, referral tree, and access key lifecycle
The Vezta rewards system is a gamification engine that drives user engagement through points, missions, login streaks, referrals, and access keys. Every action — trading, viewing markets, sharing content, referring friends — earns points tracked in a centralized ledger.
Points System
Points Ledger
Post-signup point transactions are recorded in PointsLedger (the pre-signup waitlist keeps a separate WaitlistPointsLedger keyed by waitlistEntryId):
| Field | Type | Description |
|---|---|---|
userId | UUID | User who earned points |
amount | Int | Points awarded (positive) |
source | string | Where points came from: mission, referral, streak, challenge, social-post |
sourceId | string? | Opaque reference to the originating record (mission, referral, etc.) |
createdAt | DateTime | When the entry was written |
Points are purely additive — there is no spending flow in the current system (points are used for rank/access key eligibility, not redemption).
Earning Sources
| Source | Typical Points | Trigger |
|---|---|---|
| Daily mission | 10-50 | Completing a daily task (e.g., place a trade, view 5 markets) |
| Challenge | 100-500 | Completing a time-limited challenge |
| Login streak | 5 × streak day | Logging in on consecutive days |
| Referral | 200 per level | A referred user signs up and activates their key |
| Social post | 50 | Sharing a PnL card or market to X/Twitter |
| Feature use | 10-25 | Using a specific feature (e.g., first copy trade, first tracker add) |
Missions
Mission Types
| Type | Description | Example |
|---|---|---|
| Daily | Resets every 24 hours | "View 10 markets today" |
| Feature Use | One-time action | "Execute your first copy trade" |
| Social Post | Share to external platforms | "Share your PnL to X" |
| Market View | Browse/visit markets | "Visit 20 markets" |
Mission API Flow
- Client fetches available missions:
GET /api/v1/rewards - User completes a mission — client calls:
POST /api/v1/rewards/missions/:missionId - Server validates completion, awards points, updates ledger
- Points dashboard refreshed:
GET /api/v1/rewards/points-history
Bulk claiming is supported via POST /api/v1/rewards/missions/claim-all.
Login Streaks
Tracked in LoginStreak — one row per (user, calendar day), unique on (userId, loginDate):
| Field | Type | Description |
|---|---|---|
userId | UUID | User |
loginDate | Date | A calendar day (UTC) the user logged in |
createdAt | DateTime | Row creation timestamp |
Current and longest streaks are derived by scanning consecutive loginDate rows — they are not stored columns.
Rules:
- A new row is written when the user logs in on a new calendar day (UTC)
- The current streak is the run of consecutive
loginDaterows ending today; a gap resets it - Bonus points scale with streak length:
5 × currentStreak
Referral System
The referral system uses three-tier deep earnings:
| Tier | Depth | Earnings |
|---|---|---|
| Level 1 | Direct referral | 200 points |
| Level 2 | Referral of referral | 100 points |
| Level 3 | Referral of referral of referral | 50 points |
Referral Codes
- Each user can generate a custom referral code via
POST /api/v1/rewards/referral-code - Codes are 4-12 alphanumeric characters, checked for uniqueness
- Custom codes cannot duplicate existing access keys or group codes
- Default code is the user's ID if no custom code is set
Referral Tree
GET /api/v1/rewards/referral-tree returns the user's downline tree — who they referred, who those users referred, and so on, with point earnings at each level.
Access Keys
Access keys are the gating mechanism for the beta. Users earn the ability to generate keys by accumulating points.
Key Lifecycle
enum KeyStatus {
ACTIVE = 'ACTIVE',
USED = 'USED',
REVOKED = 'REVOKED',
EXPIRED = 'EXPIRED',
}| State | Description |
|---|---|
ACTIVE | Usable for signup |
USED | Consumed by a signup (usedById set) |
EXPIRED | Past its TTL (typically 30 days) |
REVOKED | Manually disabled by admin |
Key Generation Flow
- User reaches point threshold:
GET /api/v1/rewards/access-keys/remainingshows available keys - User generates key:
POST /api/v1/rewards/access-keys/generate(optionally with custom code) - Key is created as
ACTIVEwith a 30-day expiry - User shares the key with a friend
- Friend signs up at
/access-keyusing the key - Backend activates key, sets
beta_access=1cookie, records referral
Group Codes
Group codes (managed by admins) are bulk invitation codes that don't count against a user's key limit:
| Endpoint | Method | Description |
|---|---|---|
/api/v1/admin/group-codes | POST | Create a group code |
/api/v1/admin/group-codes | GET | List all group codes |
/api/v1/admin/group-codes/:id | DELETE | Revoke a group code |
Group codes are used for promotional campaigns, waitlist batch releases, and partner invitations.
Challenges
Time-limited challenges are special missions with higher point rewards:
- Displayed via
GET /api/v1/rewards/challenges - Have start and end dates
- Examples: "Trade $1000 volume this week", "Refer 3 friends in March"
- Completed challenges award 100-500 points
- Challenges are separate from daily missions and tracked independently
Admin Access Key Management
Admins have full CRUD over access keys:
| Endpoint | Description |
|---|---|
GET /api/v1/admin/access-keys | List all keys with filters |
POST /api/v1/admin/access-keys | Create a key directly |
POST /api/v1/admin/access-keys/bulk | Generate keys in bulk |
POST /api/v1/admin/access-keys/:source/export | Export keys as CSV |
POST /api/v1/admin/access-keys/:id/revoke | Revoke a key |
POST /api/v1/admin/access-keys/:id/extend | Extend a key's TTL |
GET /api/v1/admin/access-keys/stats | Key usage statistics |