Skip to content

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 SUBSCRIBER users
  • 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 metadata
  • ChallengeQuestion: ordered prompts for a challenge
  • ChallengeOption: ordered selectable answers; score stores JSON personality points
  • ChallengeResult: possible result card content
  • ChallengeAttempt: subscriber-owned lifecycle record
  • ChallengeAttemptAnswer: 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, REFERRAL
  • ChallengeStatus: DRAFT, PUBLISHED, ARCHIVED
  • ChallengeAttemptStatus: STARTED, COMPLETED

Only PUBLISHED challenges with deletedAt = null are discoverable.

Money Personality Challenge

Seed slug: money-personality-challenge

Results:

  • SWIGGY_INVESTOR (SI) - Swiggy Investor
  • EMI_WARRIOR (EW) - EMI Warrior
  • YOLO_SPENDER (YO) - YOLO Spender
  • SALARY_SURVIVOR (SS) - Salary Survivor
  • FUTURE_BUILDER (FB) - Future Builder
  • SILENT_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:

{
  "FUTURE_BUILDER": 3,
  "SILENT_RESPONSIBLE": 1
}

Scoring rules:

  • Sum selected option points by result key.
  • Pick the result with the highest score.
  • Break ties by lowest result displayOrder, then stable resultKey sorting.
  • Compute matchPercentage as round((winningScore / totalAwardedScore) * 100).
  • Bound the percentage to 0..100.
  • If no points are awarded, return 0.

Lifecycle

  1. Subscriber lists available challenges.
  2. Subscriber opens a challenge detail screen.
  3. Subscriber starts an attempt.
  4. Subscriber submits one answer per question.
  5. Backend validates ownership, challenge status, answer coverage, and option/question membership.
  6. Backend stores answers and completion result in one transaction.
  7. Backend returns a result card with shareToken and sharePath.
  8. 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:

  • pageNumber optional integer, default 1
  • pageSize optional integer, default 10, max 100

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:

{
  "answers": [
    {
      "questionId": "question_id",
      "selectedOptionId": "option_id"
    }
  ]
}

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:

  • 400 when answers are missing, duplicated, or do not match challenge questions/options
  • 404 when challenge or attempt is not found for the subscriber
  • 409 when the attempt is already completed
  • 501 when 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.