Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vruizz22/innova-backend-serverless/llms.txt

Use this file to discover all available pages before exploring further.

The Guide Submissions API is the student-facing side of the guides workflow. Students browse the published guides assigned to their enrolled courses, upload photos of their handwritten answers to receive presigned S3 URLs, and poll asynchronous grading results once the AI pipeline has finished scoring each submission.
All endpoints in this module are mounted under /student and require a valid JWT issued to a user with the STUDENT role. Requests that carry a TEACHER or ADMIN token will be rejected with 403 Forbidden.

GET /student/guides

List every published guide that belongs to one of the authenticated student’s actively enrolled courses. Each entry includes real-time progress counters so the student can see how many questions they have already answered. Auth: JWT (STUDENT)

Response

id
string
UUID of the guide.
title
string
Display title of the guide.
description
string | null
Optional description provided by the teacher.
dueAt
string | null
ISO 8601 due-date, or null if none is set.
totalQuestions
number
Number of approved questions in the guide.
gradedQuestions
number
Number of questions the student has at least one GRADED submission for.
Example request
curl -X GET https://api.example.com/student/guides \
  -H "Authorization: Bearer <student_jwt>"

GET /student/guides/:id

Returns the quiz view of a guide — question prompts and figure attachments are included, but solution steps are always hidden. The student’s own submission states for each question are nested under each question object. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the guide to load.

Response

guide
object
Top-level guide metadata.
questions
array
Approved questions ordered by sequence, each with the student’s submission history.
Example request
curl -X GET https://api.example.com/student/guides/guide_abc123 \
  -H "Authorization: Bearer <student_jwt>"

POST /student/guides/:id/questions/:qid/submissions

Start a new submission for one guide question. The server creates a submission shell in the database and returns presigned S3 PUT URLs — one per photo the student intends to upload. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the guide.
qid
string
required
UUID of the specific question being answered.

Request body

photoCount
number
required
How many photos of the handwritten work to upload. Must be an integer between 1 and 3 (inclusive).

Response

submissionId
string
UUID of the newly created submission. Use this ID with the /complete and /status endpoints.
presignedPutUrls
string[]
Array of presigned S3 PUT URLs. Each URL corresponds to one photo slot. URLs expire after the configured TTL (default 600 s).
attemptNumber
number
The attempt index for this submission (starts at 1).
Example request
curl -X POST https://api.example.com/student/guides/guide_abc123/questions/q_def456/submissions \
  -H "Authorization: Bearer <student_jwt>" \
  -H "Content-Type: application/json" \
  -d '{"photoCount": 2}'
Example response
{
  "submissionId": "sub_11223344-...",
  "presignedPutUrls": [
    "https://s3.amazonaws.com/submissions-bucket/submissions/sub_11223344-.../photo1.jpg?X-Amz-...",
    "https://s3.amazonaws.com/submissions-bucket/submissions/sub_11223344-.../photo2.jpg?X-Amz-..."
  ],
  "attemptNumber": 1
}
Presigned PUT URLs expire quickly (default 10 minutes). The student must complete all uploads and call POST /student/submissions/:id/complete before the TTL elapses. Expired URLs will be rejected by S3 with a 403 error.

POST /student/submissions/:id/complete

Confirm that all photos have been uploaded and enqueue the submission for AI grading. The server verifies each photo is present in S3 before accepting the request. Auth: JWT (STUDENT) Returns 202 Accepted on success.

Path parameters

id
string
required
UUID of the submission to complete (returned by the createSubmission call).
Example request
curl -X POST https://api.example.com/student/submissions/sub_11223344-.../complete \
  -H "Authorization: Bearer <student_jwt>"
After calling this endpoint, poll GET /student/submissions/:id/status to track grading progress. Calling /complete again on the same submission returns 400 Bad Request.

GET /student/submissions/:id/status

Poll the grading status of a submission. Once the AI pipeline finishes, status transitions from GRADING to GRADED and the result fields are populated. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the submission to check.

Response

id
string
Submission UUID.
status
string
Current lifecycle status. One of: UPLOADED · GRADING · GRADED · FAILED.
score
number | null
Numeric score awarded by the grader, or null if not yet graded.
isCorrect
boolean | null
true if the answer was marked correct, null while pending.
errorTagCode
string | null
Machine-readable error tag code (e.g. "SIGN_ERROR"), or null.
errorTagName
string | null
Human-readable error tag label, or null.
diagnosticHint
string | null
Diagnostic hint from the error tag, shown to the student after grading.
gradedAt
string | null
ISO 8601 timestamp when grading completed, or null.
Example request
curl -X GET https://api.example.com/student/submissions/sub_11223344-.../status \
  -H "Authorization: Bearer <student_jwt>"
Example response (graded)
{
  "id": "sub_11223344-...",
  "status": "GRADED",
  "score": 8,
  "isCorrect": true,
  "errorTagCode": null,
  "errorTagName": null,
  "diagnosticHint": null,
  "gradedAt": "2024-09-01T14:32:00.000Z"
}

GET /student/guides/:id/results

Retrieve the student’s per-question grading results for a completed guide. If the teacher has enabled showSolutionAfterGrade, the current solution is also returned for questions that have been graded. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the guide.

Response

guideId
string
UUID of the guide.
showSolution
boolean
Whether solution steps are included in the response (teacher-controlled setting).
questions
array
Per-question result summary, ordered by sequence.
Example request
curl -X GET https://api.example.com/student/guides/guide_abc123/results \
  -H "Authorization: Bearer <student_jwt>"

GET /student/guides/:id/scan-page-url

Get a short-lived presigned S3 PUT URL for uploading a full-page photo. Use this URL before calling POST /student/guides/:id/scan-page to let the server auto-detect and split individual exercises. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the guide.

Response

photoKey
string
The S3 object key that was pre-allocated. Pass this value to the scan-page endpoint.
presignedUrl
string
Presigned S3 PUT URL. Upload the JPEG page photo directly to this URL from the client.
Example request
curl -X GET https://api.example.com/student/guides/guide_abc123/scan-page-url \
  -H "Authorization: Bearer <student_jwt>"

POST /student/guides/:id/scan-page

Submit a full-page scan photo for OCR-based auto-detection. The server downloads the photo from S3, runs the multi-exercise OCR pipeline, then positionally aligns each detected exercise to a guide question (exercise at index 0 → question with sequence = 1, and so on). One GuideSubmission is created per matched pair and immediately enqueued for AI grading. Auth: JWT (STUDENT)

Path parameters

id
string
required
UUID of the guide.

Request body

photoKey
string
required
The S3 object key returned by GET /student/guides/:id/scan-page-url. The photo must already be uploaded to S3 before calling this endpoint.

Response

photoKey
string
The S3 key of the page photo that was processed.
matched
number
Number of exercises successfully matched to guide questions and enqueued for grading.
submissions
array
Per-question submission summary.
Example request
curl -X POST https://api.example.com/student/guides/guide_abc123/scan-page \
  -H "Authorization: Bearer <student_jwt>" \
  -H "Content-Type: application/json" \
  -d '{"photoKey": "guide-scans/guide_abc123/student_xyz/abc.jpg"}'
Example response
{
  "photoKey": "guide-scans/guide_abc123/student_xyz/abc.jpg",
  "matched": 3,
  "submissions": [
    { "questionId": "q_001", "sequence": 1, "submissionId": "sub_aaa", "skipped": false },
    { "questionId": "q_002", "sequence": 2, "submissionId": "sub_bbb", "skipped": false },
    { "questionId": "q_003", "sequence": 3, "submissionId": "sub_ccc", "skipped": false }
  ]
}
Questions that exceed the teacher’s maxResubmissions cap are automatically skipped and appear with "skipped": true and "reason": "limit_reached". Questions beyond the detected exercise count are simply not submitted.

Submission workflow

Use this sequence for standard single-question photo submissions.
1

Start the submission

Call POST /student/guides/:id/questions/:qid/submissions with photoCount (1–3). Save the returned submissionId and presignedPutUrls.
curl -X POST .../student/guides/guide_abc/questions/q_def/submissions \
  -H "Authorization: Bearer <token>" \
  -d '{"photoCount": 1}'
2

Upload photos directly to S3

PUT each photo binary directly to the corresponding presigned URL. No authentication header is needed — the signature is embedded in the URL.
curl -X PUT "<presignedPutUrl>" \
  -H "Content-Type: image/jpeg" \
  --data-binary @answer_photo.jpg
3

Confirm completion

Call POST /student/submissions/:id/complete. The server verifies that every photo has landed in S3, then enqueues the submission for AI grading. Returns 202 Accepted.
curl -X POST .../student/submissions/sub_11223344.../complete \
  -H "Authorization: Bearer <token>"
4

Poll for grading result

Call GET /student/submissions/:id/status periodically until status is GRADED (or FAILED). A reasonable polling interval is every 5–10 seconds.
curl .../student/submissions/sub_11223344.../status \
  -H "Authorization: Bearer <token>"
5

View full guide results

Once all questions are graded, fetch the complete results page with GET /student/guides/:id/results.
curl .../student/guides/guide_abc/results \
  -H "Authorization: Bearer <token>"

Build docs developers (and LLMs) love