V1 API User
Source: OpenAPI 3.1.0 spec +
src/api/v1/user/routes.py,src/api/v1/user/schemas.pyTag: User - Profile management, phone verification, reports.
All endpoints require Bearer Token authentication. Response data is encrypted when feature flag is enabled.
GET /users/mcq-daily/sync
Summary: Sync User MCQ Daily Stats
Sync user MCQ daily stats by updated_at. Returns records updated after the cursor, filtered to day_start_epoch_ms >= sync_from_epoch_ms. Use next_cursor for next page.
Parameters
| Name | In | Required | Constraints | Description |
|---|---|---|---|---|
course_id | query | required | CourseEnum | Course ID to fetch stats for |
sync_from_epoch_ms | query | required | integer (epoch ms) | Start of day UTC. Only entries with day_start_epoch_ms >= this value |
next_cursor | query | optional | base64 string | Encoded cursor (updated_at, id). Omit for first page |
limit | query | optional | 1-100, default 50 | Max records to return |
x-dev-time | header | optional | 13 digits | Epoch ms |
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": [
{
"id": "507f1f77bcf86cd799439011_1_1714348800000",
"day_start_epoch_ms": 1714348800000,
"first_attempt_total": 15,
"first_attempt_correct": 10,
"reattempt_total": 5,
"reattempt_correct": 4,
"overall_total": 20,
"overall_correct": 14
},
{
"id": "507f1f77bcf86cd799439011_1_1714262400000",
"day_start_epoch_ms": 1714262400000,
"first_attempt_total": 8,
"first_attempt_correct": 6,
"reattempt_total": 2,
"reattempt_correct": 1,
"overall_total": 10,
"overall_correct": 7
}
],
"error": null,
"app_actions": null,
"pagination": {
"next_cursor": "eyJ1cGRhdGVkX2F0IjoxNzE0MzQ4ODAwMDAwLCJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMV8xXzE3MTQyNjI0MDAwMDAifQ==",
"prev_cursor": null,
"limit": 50,
"has_more": false
}
}
| Field | Description |
|---|---|
id | Document ID format: {user_id}_{course_id}_{day_start_epoch_ms} |
day_start_epoch_ms | Day start (00:00 UTC) in epoch ms |
first_attempt_total | Count of first-time attempts that day |
first_attempt_correct | Correct first attempts |
reattempt_total | Re-attempt count |
reattempt_correct | Correct re-attempts |
overall_total | Total attempts (first + re) |
overall_correct | Total correct |
DELETE /users
Summary: Delete User
Delete the authenticated user and log them out from all active sessions.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
x-dev-time | header | optional | Epoch ms (13 digits) |
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": {
"id": "507f1f77bcf86cd799439011",
"message": "Operation completed successfully."
},
"error": null,
"app_actions": null
}
Error Responses
| Error Code | Condition |
|---|---|
| 3507 | User deletion failed |
PATCH /users/info
Summary: Update User Info
Update user info fields. All fields are optional; only provided fields are updated.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
x-dev-time | header | optional | Epoch ms (13 digits) |
Request Body
{
"name": {
"first_name": "John",
"last_name": "Doe"
},
"background_info": "Engineering graduate, preparing for UPSC",
"attempt_number": 2,
"attempt_year": 2026
}
| Field | Type | Constraints | Description |
|---|---|---|---|
name | object | optional | { first_name: string, last_name: string } |
background_info | string | optional, max 1000 chars | Educational/professional background |
attempt_number | integer | optional, >= 1 | Exam attempt number |
attempt_year | integer | optional, 1900-2100 | Year of attempt |
Conditions:
- At least one field must be provided; error
1006(VALIDATION_FAILED) if all fields are null/missing - String fields are auto-stripped of whitespace
Success Response
Returns the full UserDetailsResponse (same shape as GET /auth/me response data).
POST /users/profile-picture
Summary: Upload Profile Picture
Upload a profile picture for the authenticated user.
Request Body - multipart/form-data
| Field | Type | Required | Constraints |
|---|---|---|---|
file | binary | required | JPEG, PNG, or WEBP only |
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": {
"filename": "profile_507f1f77.jpg",
"width": 400,
"height": 400,
"aspect_ratio": "1:1"
},
"error": null,
"app_actions": null
}
POST /users/send-phone-otp
Summary: Initiate Phone Number Validation
Send an OTP to validate the user’s phone number.
Request Body
{
"phone_number": {
"code": "+91",
"value": "9876543210"
}
}
Conditions:
codemust be"+91"(India only)valuemust be 10-15 digits
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": {
"message": "OTP sent successfully",
"expiry_time": 1714400300000,
"oti": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
},
"error": null,
"app_actions": null
}
Error Responses
| Error Code | Condition |
|---|---|
| 3708 | Phone number already registered to another account |
POST /users/verify-phone-otp
Summary: Verify Phone Number Validation
Verify the OTP and link the phone number to the user’s account.
Request Body
{
"phone_number": {
"code": "+91",
"value": "9876543210"
},
"otp": "123456",
"oti": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
All fields required. otp length must match server-configured OTP length.
Business Logic
- Verifies OTP against cache using phone_number, otp, and oti
- Revokes the OTI (one-time use)
- Updates user’s
phone_numberand setsis_phone_validated=true
Success Response
Returns the full UserDetailsResponse with updated phone number.
Error Responses
| Error Code | Condition |
|---|---|
| 2002 | OTP is incorrect |
| 2003 | OTP has expired |
| 2008 | OTI has expired |
| 3709 | Phone number already exists on this account |
POST /users/report
Summary: Create User Report
Create a user report regarding content issues (MCQ or docket).
Parameters
| Name | In | Required | Description |
|---|---|---|---|
course_id | query | required | Course ID the reported content belongs to |
x-dev-time | header | optional | Epoch ms (13 digits) |
Request Body
{
"content_id": "60d5ec49f1b2c72e4c8b4567",
"content_short_uid": "M01234",
"content_type": 2,
"issue_type": 1,
"comments": "The correct answer for this question should be option_2, not option_3. The explanation references the wrong article."
}
| Field | Required | Description |
|---|---|---|
content_id | required | MongoDB ObjectId of the MCQ or Docket |
content_short_uid | optional | Human-readable short UID (e.g. “M01234”) |
content_type | required | DOCKET=1, MCQ=2 |
issue_type | required | Default=1 |
comments | required | Detailed description of the issue |
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": {
"id": "60d5ec49f1b2c72e4c8baaaa",
"message": "Operation completed successfully."
},
"error": null,
"app_actions": null
}