POST /exercises/evaluate
Evaluates a user’s answer to an exercise. Returns score 0-10, result and feedback.
Body Fields
| Field | Type | Required | Description |
|---|---|---|---|
exerciseId | string | Yes | Exercise identifier (max 128 chars) |
area | string | Yes | listening, reading, writing, vocabulary, grammar |
type | string | Yes | See types table |
answer | string | Yes | User’s answer (max 2000 chars) |
correctAnswer | string or string[] | Conditional | Required for multiple_choice and fill_blank. Optional for open_answer. |
content | object | Conditional | Required for drag_and_drop, match, word_search, crossword. Returns 400 if missing. |
difficulty | number | No | Difficulty level 1-5 |
Supported Types
| type | Strategy | Score |
|---|---|---|
multiple_choice | Case-insensitive + trim | 0 or 10 |
fill_blank | Case-insensitive + trim, multiple alternatives | 0 or 10 |
complete | Same as fill_blank — user writes the word | 0 or 10 |
open_answer | Levenshtein >= 0.8 or minimum length | 0-10 |
drag_and_drop | Correct items / total | 0-10 |
match | Correct pairs / total | 0-10 |
word_search | Found words / total | 0-10 |
crossword | Correct answers / total, case-insensitive | 0-10 |
Response Structure
{ "correct": true, "score": 10, "feedback": "Correct!", "metadata": { "area": "vocabulary", "type": "multiple_choice" }}Examples by Type
multiple_choice
{ "exerciseId": "ex_001", "area": "vocabulary", "type": "multiple_choice", "answer": "B", "correctAnswer": "b"}“B” and “b” are equivalent (case-insensitive).
fill_blank - multiple alternatives
{ "exerciseId": "ex_002", "area": "grammar", "type": "fill_blank", "answer": "goes", "correctAnswer": ["went", "go", "goes"]}complete
Identical to fill_blank. Use when the exercise asks the user to write a word in a blank space within a text.
{ "exerciseId": "ex_002b", "area": "vocabulary", "type": "complete", "answer": "She", "correctAnswer": "She"}Accepts correctAnswer as string or array of alternatives.
open_answer
{ "exerciseId": "ex_003", "area": "writing", "type": "open_answer", "answer": "The cat is sleeping on the couch", "correctAnswer": "The cat sleeps on the sofa"}Feedback by score: "Good answer!" (>= 0.8), "Your answer is partially correct." (0.5-0.8), "Incorrect. Review the topic and try again." (< 0.5).
drag_and_drop
answer = JSON.stringify({ item_id: zone_id })
{ "exerciseId": "ex_004", "area": "vocabulary", "type": "drag_and_drop", "answer": "{\"1\":\"fruit\",\"2\":\"vegetable\"}", "content": { "items": [ { "id": "1", "text": "Apple", "correctZoneId": "fruit" }, { "id": "2", "text": "Carrot", "correctZoneId": "vegetable" } ], "zones": [ { "id": "fruit", "label": "Fruits" }, { "id": "vegetable", "label": "Vegetables" } ] }}match
answer = JSON.stringify({ left: right })
{ "exerciseId": "ex_005", "area": "vocabulary", "type": "match", "answer": "{\"Dog\":\"A loyal pet\",\"Cat\":\"A small animal\"}", "content": { "pairs": [ { "left": "Dog", "right": "A loyal pet" }, { "left": "Cat", "right": "A small animal" } ] }}word_search
answer = JSON.stringify({ found: string[] })
{ "exerciseId": "ex_006", "area": "vocabulary", "type": "word_search", "answer": "{\"found\":[\"CAT\",\"DOG\"]}", "content": { "words": ["CAT", "DOG", "BIRD"] }}content.words accepts string[] or { word, clue }[].
crossword
answer = JSON.stringify({ "clue_number": "answer" }) - keys are 1-based clue numbers.
{ "exerciseId": "ex_007", "area": "vocabulary", "type": "crossword", "answer": "{\"1\":\"cat\",\"2\":\"dog\",\"3\":\"act\"}", "content": { "words": [ { "answer": "CAT", "clue": { "type": "TEXT", "value": "A small animal" } }, { "answer": "DOG", "clue": { "type": "TEXT", "value": "A loyal pet" } }, { "answer": "ACT", "clue": { "type": "TEXT", "value": "To do something" } } ] }}Comparison is case-insensitive: “cat” === “CAT”.