Role: Assistant
Base URL:https://edutrackonline.savekiteg.com
Authentication: JWT tokens in HTTP-Only cookies (see main docs for login/refresh)
The Assistant role has LIMITED permissions — they help their assigned teacher. Most operations are read-only with some write exceptions (approve enrollments, upload materials).
Description: See all assistants working under the same teacher.
Authentication: Teacher, Assistant
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"user_id": "Integer",
"username": "String",
"name": "String",
"phone": "String",
"gmail": "String",
"gender": "String (male|female) | null",
"profile_picture": "String (URL) | null",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)",
"teacher": "Integer — Teacher ID"
}
]
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
403 |
Not a teacher/assistant | {"detail": "You do not have permission..."} |
Description: List courses taught by the teacher (the queryset filters by teacher profile).
Authentication: Teacher, Assistant
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"name": "String",
"teacher": "Integer",
"teacher_name": "String",
"grade": "Integer",
"grade_name": "String",
"subject": "Integer",
"subject_name": "String",
"description": "String | null",
"cover_picture": "String (URL) | null",
"is_active": "Boolean",
"topic_count": "Integer",
"created_at": "DateTime (ISO 8601)"
}
]
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
403 |
Not a teacher/assistant | {"detail": "You do not have permission..."} |
Description: List topics. Supports filtering by course, search, and ordering.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
course |
Integer | Filter by course ID |
is_active |
Boolean | Filter by active status |
search |
String | Search by name, description, or course name |
ordering |
String | order, created_at, name |
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"course": "Integer",
"course_name": "String",
"name": "String",
"description": "String | null",
"order": "Integer",
"is_active": "Boolean",
"lecture_count": "Integer",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a single topic with nested lectures.
Authentication: Any authenticated user
Success Response — 200 OK:
{
"id": "Integer",
"course": "Integer",
"course_name": "String",
"name": "String",
"description": "String | null",
"order": "Integer",
"is_active": "Boolean",
"lectures": [
{
"id": "Integer",
"topic": "Integer",
"topic_name": "String",
"course_name": "String",
"teacher_name": "String",
"name": "String",
"description": "String | null",
"price": "Decimal",
"discount": "Decimal",
"final_price": "Decimal",
"formatted_price": "String",
"available_days": "Integer",
"is_visible": "Boolean",
"picture": "String (URL) | null",
"order": "Integer",
"videos": "Array[Object]",
"video_count": "Integer",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
],
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Topic not found | {"detail": "Not found."} |
Description: List lectures. Supports filtering by topic, visibility, search, and ordering.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
topic |
Integer | Filter by topic ID |
is_visible |
Boolean | Filter by visibility |
search |
String | Search by name, description, or topic name |
ordering |
String | order, price, created_at, name |
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"topic": "Integer",
"topic_name": "String",
"name": "String",
"description": "String | null",
"price": "Decimal",
"discount": "Decimal",
"final_price": "Decimal",
"formatted_price": "String",
"available_days": "Integer",
"is_visible": "Boolean",
"picture": "String (URL) | null",
"order": "Integer",
"video_count": "Integer",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a single lecture with nested videos.
Authentication: Any authenticated user
Success Response — 200 OK:
{
"id": "Integer",
"topic": "Integer",
"topic_name": "String",
"course_name": "String",
"teacher_name": "String",
"name": "String",
"description": "String | null",
"price": "Decimal",
"discount": "Decimal",
"final_price": "Decimal",
"formatted_price": "String",
"available_days": "Integer",
"is_visible": "Boolean",
"picture": "String (URL) | null",
"order": "Integer",
"videos": [
{
"id": "Integer",
"lecture": "Integer",
"name": "String",
"platform": "String (youtube|bunnystream|vdocipher)",
"platform_display": "String",
"video_url": "String",
"order": "Integer",
"duration_minutes": "Integer | null",
"duration_display": "String | null",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
],
"video_count": "Integer",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
Description: Get all videos for a specific lecture.
Authentication: Any authenticated user
Success Response — 200 OK:
[
{
"id": "Integer",
"lecture": "Integer",
"name": "String",
"platform": "String (youtube|bunnystream|vdocipher)",
"platform_display": "String",
"video_url": "String",
"order": "Integer",
"duration_minutes": "Integer | null",
"duration_display": "String | null",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
]
Description: List videos. Supports filtering by lecture, platform, active status, search, and ordering.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
lecture |
Integer | Filter by lecture ID |
platform |
String | Filter by platform (youtube, bunnystream, vdocipher) |
is_active |
Boolean | Filter by active status |
search |
String | Search by name or video URL |
ordering |
String | order, created_at, duration_minutes |
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"lecture": "Integer",
"name": "String",
"platform": "String (youtube|bunnystream|vdocipher)",
"platform_display": "String",
"video_url": "String",
"order": "Integer",
"duration_minutes": "Integer | null",
"duration_display": "String | null",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a single video.
Authentication: Any authenticated user
Success Response — 200 OK:
{
"id": "Integer",
"lecture": "Integer",
"name": "String",
"platform": "String (youtube|bunnystream|vdocipher)",
"platform_display": "String",
"video_url": "String",
"order": "Integer",
"duration_minutes": "Integer | null",
"duration_display": "String | null",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Video not found | {"detail": "Not found."} |
Description: List pending enrollment requests for the teacher's courses.
Authentication: Teacher, Assistant
Success Response — 200 OK: Array of pending enrollments.
[
{
"id": "Integer",
"student": "Integer",
"student_name": "String",
"student_code": "String",
"course": "Integer",
"course_name": "String",
"grade_name": "String",
"teacher_name": "String",
"status": "String — pending",
"status_display": "String — Pending",
"enrolled_at": "DateTime (ISO 8601)",
"approved_by": "Integer | null",
"approved_by_name": "String | null",
"responded_at": "DateTime | null",
"response_note": "String | null"
}
]
Description: Approve a pending enrollment. Assistant must be assistant of the course teacher.
Authentication: Teacher (course owner), Assistant (teacher's assistant)
Content-Type: application/json
Request Body:
{
"response_note": "String (Optional) — Note for the student"
}
Success Response — 200 OK:
{
"id": "Integer",
"student": "Integer",
"student_name": "String",
"course": "Integer",
"course_name": "String",
"status": "approved",
"approved_by": "Integer | null",
"approved_by_name": "String | null",
"responded_at": "DateTime (ISO 8601)",
"response_note": "String | null"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
403 |
Not course owner | {"error": "You can only manage enrollments for your own courses"} |
400 |
Not pending | {"error": "Cannot approve enrollment with status: X"} |
404 |
Enrollment not found | {"error": "Enrollment not found"} |
Description: Reject a pending enrollment.
Authentication: Teacher (course owner), Assistant (teacher's assistant)
Content-Type: application/json
Request Body:
{
"response_note": "String (Optional) — Note for the student"
}
Success Response — 200 OK:
{
"id": "Integer",
"student": "Integer",
"student_name": "String",
"course": "Integer",
"course_name": "String",
"status": "rejected",
"approved_by": "Integer | null",
"approved_by_name": "String | null",
"responded_at": "DateTime (ISO 8601)",
"response_note": "String | null"
}
Error Responses: Same as approve endpoint.
Description: Extend a student's lecture access by adding extra days.
Authentication: Teacher (lecture course owner), Assistant
Content-Type: application/json
Request Body:
{
"extra_days": "Integer (Required) — Minimum 1"
}
Success Response — 200 OK: Updated purchase object.
{
"id": "Integer",
"student": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"topic_name": "String",
"course_name": "String",
"teacher_name": "String",
"purchased_at": "DateTime (ISO 8601)",
"expires_at": "DateTime (ISO 8601)",
"effective_expiry": "DateTime (ISO 8601)",
"amount_paid": "Decimal",
"extra_days": "Integer",
"is_expired": "Boolean",
"reopened_by": "Integer | null",
"reopened_by_name": "String | null",
"reopened_at": "DateTime | null"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
403 |
Not course owner | {"error": "You can only extend access for lectures in your own courses"} |
400 |
Invalid extra_days | {"extra_days": ["Ensure this value is greater than or equal to 1."]} |
404 |
Purchase not found | {"detail": "Not found."} |
Description: List questions accessible to the assistant.
Authentication: Teacher, Assistant
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
lesson |
Integer | Filter by lesson ID |
question_type |
String | mcq_single, mcq_multiple, written |
difficulty |
String | easy, medium, hard |
is_global |
Boolean | true or false |
lesson__chapter__subject |
Integer | Filter by subject ID |
lesson__chapter__grade |
Integer | Filter by grade ID |
search |
String | Search in question text and explanation |
Success Response — 200 OK:
{
"count": "Integer",
"results": [
{
"id": "Integer",
"lesson": "Integer",
"lesson_name": "String",
"chapter_name": "String",
"subject_name": "String",
"question_type": "String (mcq_single|mcq_multiple|written)",
"difficulty": "String (easy|medium|hard)",
"points": "Integer",
"choice_count": "Integer",
"is_global": "Boolean",
"created_by": "Integer",
"created_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a single question with all choices (including is_correct).
Authentication: Teacher, Assistant
Success Response — 200 OK:
{
"id": "Integer",
"lesson": "Integer",
"lesson_name": "String",
"chapter_name": "String",
"subject_name": "String",
"question_type": "String",
"difficulty": "String",
"points": "Integer",
"text": "String",
"image": "String (URL) | null",
"explanation": "String | null",
"is_global": "Boolean",
"choices": [
{
"id": "Integer",
"text": "String",
"image": "String (URL) | null",
"is_correct": "Boolean",
"order": "Integer"
}
],
"created_by": "Integer",
"created_by_name": "String - Creator name",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Question not found | {"detail": "Not found."} |
Description: List homeworks for the teacher's courses.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
lecture |
Integer | Filter by lecture ID |
is_active |
Boolean | Filter by active status |
is_published |
Boolean | Filter by published status |
Success Response — 200 OK:
{
"count": "Integer",
"results": [
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String",
"is_active": "Boolean",
"is_published": "Boolean",
"total_points": "Integer",
"question_count": "Integer",
"open_date": "DateTime | null",
"close_date": "DateTime | null",
"created_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a homework with questions.
Authentication: Teacher, Assistant, SiteOwner
Success Response — 200 OK:
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String",
"is_active": "Boolean",
"is_published": "Boolean",
"total_points": "Integer",
"question_count": "Integer",
"questions": [
{
"id": "Integer",
"question": {
"id": "Integer",
"text": "String"
}
}
],
"open_date": "DateTime | null",
"close_date": "DateTime | null",
"created_at": "DateTime (ISO 8601)"
}
Description: List all submissions for a homework.
Authentication: Teacher, Assistant
Success Response — 200 OK:
{
"count": "Integer",
"results": [
{
"id": "Integer",
"homework": "Integer - Homework ID",
"homework_title": "String - Homework title",
"student": "Integer",
"student_name": "String",
"student_code": "String",
"score": "String | null",
"status": "String (submitted|graded)",
"submitted_at": "DateTime (ISO 8601)"
}
]
}
Description: View a specific submission.
Authentication: Student (own submissions), Teacher, Assistant
Success Response — 200 OK:
{
"id": "Integer",
"homework": "Integer",
"homework_title": "String",
"student": "Integer",
"student_name": "String",
"student_code": "String - Student code",
"score": "String | null",
"model_answer": "String - Model answer",
"status": "String (submitted|graded)",
"answers": [
{
"homework_question": "Integer - Homework question ID",
"question_text": "String",
"selected_choice": "Object | null",
"selected_choice_text": "String - Text of selected choice",
"is_correct": "Boolean | null",
"points_earned": "Integer | null - Points earned"
}
],
"submitted_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Submission not found | {"detail": "Not found."} |
Description: List quizzes for the teacher's courses.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
lecture |
Integer | Filter by lecture ID |
is_active |
Boolean | Filter by active status |
is_published |
Boolean | Filter by published status |
Success Response — 200 OK:
{
"count": "Integer",
"results": [
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String",
"passing_score": "String | null",
"is_active": "Boolean",
"is_published": "Boolean",
"total_points": "Integer",
"question_count": "Integer",
"settings": {
"open_date": "DateTime | null",
"close_date": "DateTime | null",
"timer_minutes": "Integer - Time limit in minutes (0 = no limit)",
"score_visibility": "String",
"answers_visibility": "String",
"question_order": "String",
"shuffle_choices": "Boolean",
"allow_multiple_attempts": "Boolean",
"max_attempts": "Integer - Maximum attempts (0 = unlimited)",
"attempt_scoring": "String",
"show_correct_after_submission": "Boolean"
},
"created_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a quiz with questions and settings.
Authentication: Teacher, Assistant, SiteOwner
Success Response — 200 OK:
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String",
"passing_score": "String | null",
"is_active": "Boolean",
"is_published": "Boolean",
"total_points": "Integer",
"question_count": "Integer",
"settings": {
"open_date": "DateTime | null",
"close_date": "DateTime | null",
"timer_minutes": "Integer | null",
"score_visibility": "String",
"answers_visibility": "String",
"question_order": "String",
"shuffle_choices": "Boolean",
"allow_multiple_attempts": "Boolean",
"max_attempts": "Integer | null",
"attempt_scoring": "String",
"show_correct_after_submission": "Boolean"
},
"questions": [
{
"id": "Integer",
"order": "Integer",
"question": {
"id": "Integer",
"text": "String",
"question_type": "String",
"difficulty": "String",
"points": "Integer"
}
}
],
"created_at": "DateTime (ISO 8601)"
}
Description: View a specific quiz submission.
Authentication: Student (own submissions), Teacher, Assistant
Success Response — 200 OK:
{
"id": "Integer",
"quiz": "Integer",
"quiz_title": "String",
"student": "Integer",
"student_name": "String",
"attempt_number": "Integer",
"score": "String | null",
"passed": "Boolean | null",
"started_at": "DateTime (ISO 8601)",
"submitted_at": "DateTime (ISO 8601)",
"student_code": "String - Student code",
"is_timed_out": "Boolean - Whether the attempt timed out",
"score_visible": "Boolean - Whether score is visible to student",
"answers_visible": "Boolean - Whether answers are visible to student",
"answers": [
{
"quiz_question": "Integer - Quiz question ID",
"question_text": "String",
"written_answer": "String | null",
"points_earned": "Integer - Points earned",
"selected_choices": "Array[Integer] - Selected choice IDs",
"selected_choice_texts": "Array[String] - Choice texts",
"is_correct": "Boolean | null - Whether the answer is correct",
"display_order": "Integer - Display order of the question"
}
]
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Submission not found | {"detail": "Not found."} |
Description: Upload a new PDF study material.
Authentication: SiteOwner, Teacher, Assistant
Content-Type: multipart/form-data
Request Body:
{
"lecture": "Integer (Required) — Lecture ID",
"title": "String (Required)",
"description": "String (Optional)",
"file": "<PDF_FILE (Required)>"
}
Validation:
Success Response — 201 Created:
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"course_name": "String - Course name",
"title": "String",
"description": "String | null",
"file": "String (URL) - File URL",
"file_url": "String (URL)",
"is_active": "Boolean",
"created_by": "Integer - Creator user ID",
"created_by_name": "String - Creator name",
"created_at": "DateTime (ISO 8601)",
"updated_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
400 |
File too large | {"file": ["File too large. Size should not exceed 50 MB."]} |
400 |
Invalid file type | {"file": ["File extension 'xyz' is not allowed. Allowed extensions are: pdf."]} |
Description: List study materials for the teacher's courses.
Authentication: Any authenticated user
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
lecture |
Integer | Filter by lecture ID |
is_active |
Boolean | Filter by active status |
Success Response — 200 OK:
{
"count": "Integer",
"results": [
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String | null",
"file_url": "String (URL)",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)"
}
]
}
Description: Retrieve a single material.
Authentication: SiteOwner, Teacher, Assistant
Success Response — 200 OK:
{
"id": "Integer",
"lecture": "Integer",
"lecture_name": "String",
"title": "String",
"description": "String | null",
"file_url": "String (URL)",
"is_active": "Boolean",
"created_at": "DateTime (ISO 8601)"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Material not found | {"detail": "Not found."} |
Description: Update a material (replace PDF, change title, etc.).
Authentication: SiteOwner, Teacher, Assistant
Content-Type: multipart/form-data
Request Body:
{
"lecture": "Integer (Optional) — Lecture ID",
"title": "String (Optional)",
"description": "String (Optional)",
"file": "<PDF_FILE (Optional)>"
}
Success Response — 200 OK: Updated material object.
Description: Delete a material.
Authentication: SiteOwner, Teacher, Assistant
Success Response — 204 No Content
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Material not found | {"detail": "Not found."} |
Description: List all notifications for the authenticated assistant.
Authentication: Any authenticated user
Success Response — 200 OK:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": [
{
"id": "Integer",
"notification_type": "String",
"notification_type_display": "String",
"title": "String",
"message": "String",
"metadata": "Object | null",
"is_read": "Boolean",
"created_at": "DateTime (ISO 8601)"
}
]
}
Description: Get the count of unread notifications.
Authentication: Any authenticated user
Success Response — 200 OK:
{
"count": "Integer - Number of unread notifications"
}
Description: Mark all notifications as read.
Authentication: Any authenticated user
Content-Type: application/json
Request Body: None
Success Response — 200 OK:
{
"message": "All notifications marked as read"
}
Description: Mark a single notification as read.
Authentication: Any authenticated user
Content-Type: application/json
Request Body: None
Success Response — 200 OK:
{
"message": "Notification marked as read"
}
Error Responses:
| Status | Condition | Response Body |
|---|---|---|
404 |
Notification not found | {"detail": "Not found."} |
| Status | Condition | Response Body |
|---|---|---|
401 Unauthorized |
Not authenticated | {"detail": "Authentication credentials were not provided."} |
401 Unauthorized |
Token expired | {"error": "Invalid or expired refresh token"} |
403 Forbidden |
Insufficient permissions | {"detail": "You do not have permission to perform this action."} |
404 Not Found |
Object does not exist | {"detail": "Not found."} or {"error": "String"} |
500 Internal Server Error |
Unexpected error | {"detail": "Internal server error"} |
List endpoints return:
{
"count": "Integer",
"next": "String (URL) | null",
"previous": "String (URL) | null",
"results": "Array[Object]"
}
Add ?all=true to bypass pagination.