V1 API MCQ
Source: OpenAPI 3.1.0 spec +
src/api/v1/mcq/routes.py,src/api/v1/mcq/schemas.pyTag: MCQ - MCQ questions and operations.
All endpoints require Bearer Token authentication. Response data is encrypted when feature flag is enabled.
GET /mcqs/sync
Summary: List PYQ MCQs by Updated At (sync)
Retrieve a paginated list of PYQ MCQs with forward-only pagination by updated_at. Only PYQs are returned (DQ/EQ excluded). Filter by year or taxonomy_id, not both.
Parameters
| Name | In | Required | Constraints | Description |
|---|---|---|---|---|
course_id | query | required | CourseEnum | Course ID |
limit | query | optional | 1-120, default 10 | Number of results to return |
year | query | optional | integer | Filter MCQs by year (e.g. 2023). Mutually exclusive with taxonomy_id |
taxonomy_id | query | optional | ObjectId string | Filter MCQs by taxonomy ID. Mutually exclusive with year |
next_cursor | query | optional | base64 string | Forward pagination cursor from previous response |
prev_cursor | query | optional | base64 string | Backward pagination cursor |
x-dev-time | header | optional | 13 digits | Epoch ms |
Conditions:
yearandtaxonomy_idare mutually exclusive. If both provided: error1003(INVALID_PARAMETERS) with message “Use either year or taxonomy_id, not both.”taxonomy_idis converted to PydanticObjectId internally; invalid format raises error
Business Logic
- Decodes cursor (if provided) to get last
updated_at+id - Queries MCQs with:
course_id,yearortaxonomy_idfilter,updated_at > cursor.updated_at - Fetches associated blocks for each MCQ via
BlockService.get_blocks_for_mcqs() - Builds response with next_cursor from last item’s (updated_at, id)
Success Response
{
"status": "success",
"is_data_encrypted": 0,
"data": [
{
"id": "60d5ec49f1b2c72e4c8b4567",
"display_uid": "UPSC-POL-001",
"short_uid": "M00123",
"question": "Which article of the Indian Constitution deals with the Right to Equality?",
"question_format": 1,
"q_pview": "Which article of the Indian Constitution deals with the Right to Equality?",
"option_1": "Article 12",
"selected_option_1_count": 245,
"option_2": "Article 14",
"selected_option_2_count": 1893,
"option_3": "Article 19",
"selected_option_3_count": 312,
"option_4": "Article 21",
"selected_option_4_count": 189,
"correct_option": "option_2",
"question_type": 1,
"year": 2023,
"root_taxonomy_id": "60d5ec49f1b2c72e4c8b0001",
"taxonomy_ids": [
"60d5ec49f1b2c72e4c8b0001",
"60d5ec49f1b2c72e4c8b0002",
"60d5ec49f1b2c72e4c8b0003"
],
"sole": "U2FsdGVkX1+abc123encrypted...",
"sort_order": 15,
"tag_ids": [
"60d5ec49f1b2c72e4c8baaaa"
],
"docket_id": "60d5ec49f1b2c72e4c8bdddd",
"is_deleted": false,
"ordered_block_ids": ["B001", "B002"],
"block_details": [
{
"id": "60d5ec49f1b2c72e4c8beeee",
"short_uid": "B001",
"docket_id": "60d5ec49f1b2c72e4c8bdddd",
"title": "Right to Equality - Key Provisions",
"conte": "U2FsdGVkX1+xyz789encrypted...",
"is_deleted": false
}
]
}
],
"error": null,
"app_actions": null,
"pagination": {
"next_cursor": "eyJ1cGRhdGVkX2F0IjoxNzE0NDAwMDAwMDAwLCJpZCI6IjYwZDVlYzQ5ZjFiMmM3MmU0YzhiNDU2NyJ9",
"prev_cursor": null,
"limit": 10,
"has_more": true
}
}
Field Details
| Field | Type | Description |
|---|---|---|
question_format | integer | SIMPLE_MCQ=1 (plain string), ADVANCED_MCQ=2 (PlateJS JSON) |
q_pview | string | Plain text preview. Simple MCQ: question with newlines as spaces. Advanced: extracted plain text |
correct_option | string | "option_1", "option_2", "option_3", or "option_4" |
question_type | integer | PYQ=1, DQ=2, EQ=3 |
taxonomy_ids | array | Hierarchical order: [L1_root, L2_parent, L3_leaf] |
sole | string/null | At-rest encrypted solution. Clients decrypt using short_uid-derived keys. null if no solution |
docket_id | ObjectId/null | L4 taxonomy leaf docket. Same taxonomy_ids as this MCQ |
block_details[].conte | string/null | At-rest encrypted block content (CryptoV2.1, short_uid-derived keys) |
selected_option_N_count | integer | How many users selected this option (community stats) |
Error Response Example
{
"status": "failure",
"is_data_encrypted": 0,
"data": null,
"error": {
"code": 1003,
"message": "Use either year or taxonomy_id, not both."
},
"app_actions": null
}
GET /mcqs/batch
Summary: Get MCQs by IDs
Retrieve up to 100 MCQs by MongoDB ObjectId or short_uid. Missing IDs are silently omitted (no error per ID).
Parameters
| Name | In | Required | Constraints | Description |
|---|---|---|---|---|
course_id | query | required | CourseEnum | Course ID |
ids | query | required | min 1 char | Comma-separated list of MCQ IDs or short UIDs |
x-dev-time | header | optional | 13 digits | Epoch ms |
Conditions:
- Maximum 100 IDs per request; error
1003if exceeded - Minimum 1 ID required; error
1003if empty - Each ID must be <= 25 characters; error
1003if longer - IDs are auto-stripped of whitespace
- Can mix ObjectIds and
short_uidvalues in the same request
Success Response
Same MCQDetailsListResponse[] shape as /mcqs/sync response data, but without pagination. Returns only MCQs that were found; missing IDs are omitted silently.
{
"status": "success",
"is_data_encrypted": 0,
"data": [
{
"id": "60d5ec49f1b2c72e4c8b4567",
"short_uid": "M00123",
"question": "Which article of the Indian Constitution...",
"option_1": "Article 12",
"option_2": "Article 14",
"option_3": "Article 19",
"option_4": "Article 21",
"correct_option": "option_2",
"question_type": 1,
"year": 2023,
"taxonomy_ids": ["60d5ec49f1b2c72e4c8b0001", "60d5ec49f1b2c72e4c8b0002", "60d5ec49f1b2c72e4c8b0003"],
"block_details": [ ... ]
}
],
"error": null,
"app_actions": null
}
Error Response Example
{
"status": "failure",
"is_data_encrypted": 0,
"data": null,
"error": {
"code": 1003,
"message": "Maximum 100 IDs allowed per request."
},
"app_actions": null
}