EduTrack Online - Assistant API

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).


Table of Contents

  1. View Coworkers
  2. View Teacher's Courses
  3. View Topics (Read-Only)
  4. View Lectures (Read-Only)
  5. View Videos (Read-Only)
  6. Enrollments
  7. Purchases
  8. Question Bank (Read-Only)
  9. Homeworks (Read-Only)
  10. Quizzes (Read-Only)
  11. Study Materials
  12. Notifications

1. View Coworkers

GET /accounts/teacher/assistants/

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..."}

2. View Teacher's Courses

GET /courses/my_courses/

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..."}

3. View Topics (Read-Only)

GET /courses/topics/

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)" } ] }

GET /courses/topics//

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."}

4. View Lectures (Read-Only)

GET /courses/lectures/

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)" } ] }

GET /courses/lectures//

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)" }

GET /courses/lectures//videos/

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)" } ]

5. View Videos (Read-Only)

GET /courses/videos/

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)" } ] }

GET /courses/videos//

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."}

6. Enrollments

GET /courses/enrollments/pending/

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" } ]

POST /courses/enrollments//approve/

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"}

POST /courses/enrollments//reject/

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.


7. Purchases

PATCH /courses/purchases//reopen/

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."}

8. Question Bank (Read-Only)

GET /question-bank/questions/

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)" } ] }

GET /question-bank/questions//

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."}

9. Homeworks (Read-Only)

GET /learning/homeworks/

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)" } ] }

GET /learning/homeworks//

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)" }

GET /learning/homeworks//submissions/

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)" } ] }

GET /learning/homework-submissions//

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."}

10. Quizzes (Read-Only)

GET /learning/quizzes/

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)" } ] }

GET /learning/quizzes//

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)" }

GET /learning/quiz-submissions//

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."}

11. Study Materials

POST /materials/

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."]}

GET /materials/

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)" } ] }

GET /materials//

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."}

PUT /materials//

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.


DELETE /materials//

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."}

12. Notifications

GET /notifications/

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)" } ] }

GET /notifications/unread-count/

Description: Get the count of unread notifications.

Authentication: Any authenticated user

Success Response — 200 OK:

{ "count": "Integer - Number of unread notifications" }

POST /notifications/mark-all-read/

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" }

POST /notifications//mark-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."}

Common Error Formats

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"}

Pagination

List endpoints return:

{ "count": "Integer", "next": "String (URL) | null", "previous": "String (URL) | null", "results": "Array[Object]" }

Add ?all=true to bypass pagination.