Assignments & Submissions
Assignments live inside lessons and allow teachers to collect file-based work from students. Each assignment defines accepted file types, size limits, and an optional due date. Students submit files via multipart upload and can withdraw their submission before the due date.
Assignment Entity
{
"id": "asgn_001",
"lesson_id": "les_456",
"title": "Implement Bubble Sort",
"instructions": "Write a Python function that sorts a list using bubble sort.",
"due_at": "2026-04-01T23:59:00Z",
"visibility_state": "DRAFT",
"allowed_file_types": ["py", "txt"],
"max_file_size_mb": 10,
"weight": 1.0,
"order_index": 1
}
Field notes:
due_at— ISO 8601 UTC timestamp.nullmeans no due date.allowed_file_types— list of file extensions (without dots) allowed for submission. Empty array means all types are accepted.max_file_size_mb— per-file upload limit in megabytes.weight— relative weight used when computing lesson grade averages. Default1.0.order_index— display order within the lesson.
Submission Entity
{
"id": "sub_001",
"assignment_id": "asgn_001",
"student_user_id": "usr_456",
"status": "SUBMITTED",
"is_late": false,
"submitted_at": "2026-03-30T14:22:00Z",
"files": [
{
"id": "file_001",
"original_name": "bubble_sort.py",
"mime_type": "text/x-python",
"file_size_bytes": 1024
}
]
}
status values:
| Status | Description |
|---|---|
NOT_SUBMITTED | Student has not yet submitted. |
SUBMITTED | Submission is active. |
WITHDRAWN | Student withdrew their submission. |
is_late — true when submitted_at is after due_at. Calculated server-side.
Assignment Endpoints
GET /api/v1/lessons/{lessonId}/assignments
List all assignments for a lesson.
Authentication: Required — approved class member or global ADMIN.
Visibility:
- Students see only published assignments.
- Teachers/Admins see all assignments regardless of
visibility_state.
Response: Ordered list of assignment objects.
POST /api/v1/lessons/{lessonId}/assignments
Create a new assignment within a lesson.
Authentication: Required — class TEACHER or global ADMIN.
Request:
{
"title": "Implement Bubble Sort",
"instructions": "Write a Python function that sorts a list using bubble sort.",
"due_at": "2026-04-01T23:59:00Z",
"allowed_file_types": ["py", "txt"],
"max_file_size_mb": 10,
"weight": 1.0,
"order_index": 1
}
Only title is required. Newly created assignments have visibility_state: "DRAFT".
Response: Created assignment object with 201 Created.
GET /api/v1/assignments/{id}
Retrieve a single assignment by ID.
Authentication: Required — approved class member (published only) or class TEACHER/global ADMIN.
PATCH /api/v1/assignments/{id}
Update assignment fields.
Authentication: Required — class TEACHER or global ADMIN.
Request: Any subset of { "title", "instructions", "due_at", "allowed_file_types", "max_file_size_mb", "weight", "order_index" }.
POST /api/v1/assignments/{id}/publish
Publish an assignment, making it visible to students.
Authentication: Required — class TEACHER or global ADMIN.
Request body: Empty.
POST /api/v1/assignments/{id}/unpublish
Revert a published assignment to draft, hiding it from students.
Authentication: Required — class TEACHER or global ADMIN.
Request body: Empty.
Unpublishing an assignment with existing submissions does not delete those submissions, but students will no longer be able to see the assignment or withdraw their submission while it is in draft state.
Submission Endpoints
POST /api/v1/assignments/{assignmentId}/submit
Submit files for an assignment.
Authentication: Required — STUDENT global role with approved class membership.
Content-Type: multipart/form-data
Form fields:
| Field | Description |
|---|---|
files | One or more files. Each file must match allowed_file_types and max_file_size_mb. |
Behavior:
- If the student has a prior
SUBMITTEDsubmission, it is replaced by this one (re-submission). is_lateis set automatically by comparing submission time todue_at.
Response: Created or updated submission object with 201 Created.
POST /api/v1/submissions/{submissionId}/withdraw
Withdraw an active submission.
Authentication: Required — submission owner (student).
Precondition: The assignment must not have passed its due_at. Returns PRECONDITION_FAILED if the due date has passed.
Request body: Empty.
Response: Updated submission object with status: "WITHDRAWN".
GET /api/v1/assignments/{assignmentId}/submissions/{studentId}
Retrieve a specific student's submission for an assignment.
Authentication: Required — class TEACHER or global ADMIN.
Response: Submission object including the files array.
GET /api/v1/submissions/{submissionId}/files/{fileId}/download
Download a single submitted file.
Authentication: Required — submission owner (student) or class TEACHER/global ADMIN.
Response: Raw file stream with Content-Disposition: attachment. Not a JSON envelope.