# Answer a practice card

Source: https://workroad.app/docs/api/answer-practice-card

`POST https://workroad.app/api/v1/practice-sessions/{sessionId}/answers`

Records the user's answer to one card from the session as an FSRS review, schedules the card's next due time, and counts toward the daily goal and the streak, exactly like an answer in the app. Show the term, let the user answer, reveal the definition, then send how well they recalled it. Answering the same `itemId` again with the same rating records nothing and returns `replayed: true`, so a retry is safe. `remaining` says how many cards from the last read are left; at 0, call `getPracticeSession`.

- MCP tool: `answerPracticeCard` on `https://workroad.app/api/mcp`
- Required scopes: activity:create
- Test mode: `POST https://workroad.app/api/test/v1/practice-sessions/{sessionId}/answers` checks the request and returns the example response without changing anything.
- Next: when `remaining` is 0, call `getPracticeSession` for more cards.

## Path parameters

- `sessionId`: string (uuid), required. Practice session id from `startPracticeSession`, scoped to the key's user.

## Headers

- `Idempotency-Key`: string, optional, 1-255 visible ASCII characters. Makes the POST safe to retry: a retry with the same key and body replays the first response, and the same key with a different body returns 409 `idempotency_conflict`. Kept for 24 hours. Over MCP it is the `idempotencyKey` argument.

## Request body

JSON.

- `itemId`: string (uuid), required. `itemId` of a card from `getPracticeSession`.
- `rating`: one of `"again"`, `"hard"`, `"good"`, `"easy"`, required. How well the user recalled the card: `again` (forgot), `hard`, `good` or `easy`. Ask the user, or judge their answer against the definition.
- `durationMs`: integer, required, 0 to 600000. Time the user spent on the card, 0-600000 ms. Stored in whole seconds, and counted by the daily minutes goal.

## Response

`201` Created

`200` This item was already answered. The body has `replayed: true`.

- `data`: object, required
  - `itemId`: string (uuid), required
  - `cardId`: string or null, required. Null for a cram answer on a new term.
  - `recorded`: one of `"review"`, `"cram"`, required. `review`: an FSRS review was recorded and the card rescheduled, exactly as in the app. `cram`: a cram session, nothing rescheduled; an `again` answer queues the term again.
  - `replayed`: boolean, required. True when this item was already answered. Nothing changed.
  - `queue`: one of `"new"`, `"learning"`, `"relearning"`, `"review"` or null, required. The card's queue after the review. Null for cram.
  - `due`: string (date-time) or null, required. When the card is next due. Null for cram.
  - `suspended`: boolean, required. True when the answer suspended the card as a leech.
  - `remaining`: integer, required. Cards from the last read still waiting for an answer. At 0, call `getPracticeSession` to refill.

### Example

```json
{
  "data": {
    "itemId": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
    "cardId": "3e2d1c0b-9a8f-4e7d-8c6b-5a4f3e2d1c0b",
    "recorded": "review",
    "replayed": false,
    "queue": "review",
    "due": "2026-02-05T12:00:00.000Z",
    "suspended": false,
    "remaining": 0
  }
}
```

## Errors

Every error has the body `{ "error": { "code", "message", "details" } }`.

- `400`: Invalid request body or query
- `401`: Missing, invalid, disabled or expired API key
- `403`: The API key lacks the required scope
- `404`: `not_found`: the session doesn't exist, expired, or has no such `itemId`.
- `405`: Method not allowed. Use a method from the Allow header.
- `409`: `conflict` with `details.reason`: `card-changed-refresh-session` (the card was reviewed or changed elsewhere; read the session again), `card-not-due`, `card-suspended`, `card-deleted`, `new-card-limit` or `review-card-limit`; `concurrent-grade` with `Retry-After: 1` (retry the same call). `idempotency_conflict` when the item was already answered with a different rating. The Idempotency-Key was reused with a different request body, or a request with the same key is still in progress.
- `429`: Rate limit exceeded. Wait for Retry-After before retrying. The rate-limit headers are absent when the key's own limiter rejected the request before the per-endpoint bucket check ran.
- `500`: Internal server error
