Challenges¶
Challenges are lightweight, shareable in-app activities that subscribers can discover, start, complete, and share. The first launch challenge is the Money Personality Challenge, a playful personality quiz that returns one of six result cards.
Launch Scope¶
- API version:
v2 - Audience: authenticated
SUBSCRIBERusers - Public access: completed result cards can be fetched by share token
- Content source: seeded database records
- Supported completion engine:
PERSONALITY - Not included yet: admin CRUD, leaderboards, badges, rewards, streaks, friend comparison, or server-side share-card image generation
Data Model¶
Challenges are stored as normalized PostgreSQL data through Prisma:
Challenge: discovery card and status metadataChallengeQuestion: ordered prompts for a challengeChallengeOption: ordered selectable answers;scorestores JSON personality pointsChallengeResult: possible result card contentChallengeAttempt: subscriber-owned lifecycle recordChallengeAttemptAnswer: selected option per question
participantsCount in challenge card responses is a live count of distinct subscribers with at least one attempt for the challenge. It is derived from ChallengeAttempt, not from the cached Challenge.participantsCount column.
Key enums:
ChallengeCategory:PERSONALITY,QUIZ,PUZZLE,PREDICTION,POLL,HABIT,REFERRALChallengeStatus:DRAFT,PUBLISHED,ARCHIVEDChallengeAttemptStatus:STARTED,COMPLETED
Only PUBLISHED challenges with deletedAt = null are discoverable.
Money Personality Challenge¶
Seed slug: money-personality-challenge
Results:
SWIGGY_INVESTOR(SI) - Swiggy InvestorEMI_WARRIOR(EW) - EMI WarriorYOLO_SPENDER(YO) - YOLO SpenderSALARY_SURVIVOR(SS) - Salary SurvivorFUTURE_BUILDER(FB) - Future BuilderSILENT_RESPONSIBLE(SR) - Silent Responsible
Seeded questionnaire:
| Question | Option | Points |
|---|---|---|
| Your salary comes. What do you do first? | Order food | SI +3 |
| Your salary comes. What do you do first? | Pay EMI | EW +3 |
| Your salary comes. What do you do first? | Save some money | FB +3 |
| Your salary comes. What do you do first? | Buy something I wanted | YO +3 |
| Your salary comes. What do you do first? | Send money home | SR +3 |
| How many times do you check your bank balance? | Never | SI +2, YO +1 |
| How many times do you check your bank balance? | Only before payments | SS +2 |
| How many times do you check your bank balance? | Daily | FB +2 |
| How many times do you check your bank balance? | After every spending regret | SI +2, SS +1 |
| Big sale online. Your reaction? | NEED THIS. | YO +3 |
| Big sale online. Your reaction? | Add to cart | SI +2 |
| Big sale online. Your reaction? | Ignore | FB +3 |
| Big sale online. Your reaction? | Buy first, think later | YO +4 |
| What hurts more? | Missing a trip | YO +2 |
| What hurts more? | Low account balance | SS +2 |
| What hurts more? | No savings | FB +3 |
| What hurts more? | Friends judging lifestyle | YO +3 |
| Your account balance becomes low. What do you usually do? | Ignore it and continue spending | SI +3 |
| Your account balance becomes low. What do you usually do? | Borrow from friends / credit card | EW +3 |
| Your account balance becomes low. What do you usually do? | Cut spending immediately | FB +2 |
| Your account balance becomes low. What do you usually do? | Wait for next salary and survive somehow | SS +3 |
| Your account balance becomes low. What do you usually do? | Look for extra income opportunities | SR +2, FB +1 |
Each selected option contributes points to one or more result keys. Example:
Scoring rules:
- Sum selected option points by result key.
- Pick the result with the highest score.
- Break ties by lowest result
displayOrder, then stableresultKeysorting. - Compute
matchPercentageasround((winningScore / totalAwardedScore) * 100). - Bound the percentage to
0..100. - If no points are awarded, return
0.
Lifecycle¶
- Subscriber lists available challenges.
- Subscriber opens a challenge detail screen.
- Subscriber starts an attempt.
- Subscriber submits one answer per question.
- Backend validates ownership, challenge status, answer coverage, and option/question membership.
- Backend stores answers and completion result in one transaction.
- Backend returns a result card with
shareTokenandsharePath. - Anyone with the share path can view share-safe result data.
V2 API¶
All protected endpoints require a bearer token for a SUBSCRIBER.
List Challenges¶
GET /v2/subscribers/challenges
Query:
pageNumberoptional integer, default1pageSizeoptional integer, default10, max100
Response data:
{
"count": 1,
"hasPreviousPage": false,
"hasNextPage": false,
"pageNumber": 1,
"pageSize": 10,
"totalPages": 1,
"challenges": [
{
"id": "challenge_id",
"slug": "money-personality-challenge",
"title": "Money Personality Challenge",
"description": "Answer a few playful questions and reveal your money personality.",
"category": "PERSONALITY",
"difficulty": "Easy",
"durationMinutes": 2,
"participantsCount": 0,
"isTrending": true,
"isNew": true
}
]
}
Get Challenge Detail¶
GET /v2/subscribers/challenges/:challengeId
Response data includes challenge card fields plus:
status- ordered
questions - ordered
options - possible
results
Option scoring metadata is not part of the API response.
Start Attempt¶
POST /v2/subscribers/challenges/:challengeId/attempts
Creates a STARTED attempt for the authenticated subscriber.
Response data:
{
"id": "attempt_id",
"challengeId": "challenge_id",
"userId": "subscriber_user_id",
"status": "STARTED",
"challenge": {},
"result": null,
"matchPercentage": null,
"shareToken": null,
"startedAt": "2026-06-03T00:00:00.000Z",
"completedAt": null,
"resultCard": null
}
Complete Attempt¶
POST /v2/subscribers/challenges/:challengeId/attempts/:attemptId/complete
Body:
Response data:
{
"attemptId": "attempt_id",
"challenge": {},
"result": {
"id": "result_id",
"challengeId": "challenge_id",
"resultKey": "FUTURE_BUILDER",
"title": "Future Builder",
"iconKey": "challenge-money-future-builder",
"description": "You are quietly building a better tomorrow.",
"shareTitle": "I got Future Builder on Dichit",
"shareBody": "My money personality is planning ahead.",
"displayOrder": 5
},
"matchPercentage": 75,
"shareToken": "share_token",
"sharePath": "/v2/public/challenges/results/share_token",
"completedAt": "2026-06-03T00:00:00.000Z"
}
Errors:
400when answers are missing, duplicated, or do not match challenge questions/options404when challenge or attempt is not found for the subscriber409when the attempt is already completed501when the challenge category has no completion engine yet
Get Attempt¶
GET /v2/subscribers/challenges/attempts/:attemptId
Returns the authenticated subscriber's attempt. Completed attempts include resultCard; started attempts return resultCard: null.
Public Share Result¶
GET /v2/public/challenges/results/:shareToken
No authentication required. Returns only share-safe result card data. It does not expose selected answers or private subscriber profile data.
Future Expansion¶
The current schema can support additional challenge categories by adding category-specific completion use cases while reusing discovery, attempts, result cards, and public sharing. Future features should add new tables only when needed for their behavior, such as leaderboard entries, badges, streaks, referrals, prediction settlement, or reward fulfillment.