POST /api/v1/exam/{id}/finish-attempt/{attempt}

Submit student answers for an exam attempt. For STRUCTURED questions, answers are auto-graded immediately. For UNSTRUCTURED questions, the system runs AI analysis and may auto-award scores if responses meet the authenticity threshold set by the admin.

Path parameters

  • attempt string Required

    UUID of the attempt to submit

  • id Required

    UUID of the exam (for route context)

application/json

Body Required

Student answers payload containing responses to all questions

  • answers array[object] Required
    Hide answers attributes Show answers attributes object
    • questionId string Required
    • response string
    • selectedOptions array[string]

Responses

  • 200 application/json

    Exam attempt submitted successfully. Returns grading status for structured and unstructured questions.

  • 400 application/json

    Invalid submission - missing answers, already submitted, or attempt expired

  • 404

    Attempt not found

POST /api/v1/exam/{id}/finish-attempt/{attempt}
curl \
 --request POST 'http://localhost:3500/api/v1/exam/123e4567-e89b-12d3-a456-426614174000/finish-attempt/attempt-123' \
 --header "Content-Type: application/json" \
 --data '{"answers":[{"questionId":"q1-uuid","selectedOptions":["O(log n)"]},{"questionId":"q2-uuid","responseText":"A stack follows LIFO (Last In First Out) principle..."}]}'
Request example
{
  "answers": [
    {
      "questionId": "q1-uuid",
      "selectedOptions": [
        "O(log n)"
      ]
    },
    {
      "questionId": "q2-uuid",
      "responseText": "A stack follows LIFO (Last In First Out) principle..."
    }
  ]
}
Response examples (200)
{
  "message": "Exam attempt submitted successfully",
  "maxScore": 100,
  "attemptId": "attempt-123",
  "totalScore": 85,
  "submittedAt": "2025-11-20T10:45:00Z",
  "autoGradedQuestions": 8,
  "manualGradingRequired": 2
}
Response examples (400)
{
  "error": "Bad Request",
  "message": "Attempt already submitted",
  "statusCode": 400
}
{
  "error": "Bad Request",
  "message": "Attempt time has expired",
  "statusCode": 400
}