# Get today's study overview

Source: https://workroad.app/docs/api/get-today

`GET https://workroad.app/api/v1/today`

Answers "what should I study now?" in one call. Returns the flashcards due now by subject and set, today's goal, streak and new-card limit, overdue and upcoming tasks, today's lessons and planned study blocks, and `suggestions`: what to do next, most useful first, each naming the tool and arguments that act on it. Each section needs its own scope (`activity:view`, `tasks:view`, `schedule:view`) and is null without it. Lessons from external calendars are read live and can take a few seconds.

- MCP tool: `getToday` on `https://workroad.app/api/mcp`
- Required scopes: activity:view or tasks:view or schedule:view
- Test mode: `GET https://workroad.app/api/test/v1/today` checks the request and returns the example response without changing anything.
- Next: act on the first suggestion, for example `startPracticeSession` with its arguments.

## Response

`200` OK

- `data`: object, required
  - `date`: string, required. Today (YYYY-MM-DD) in the user's time zone.
  - `timeZone`: string, required. The user's time zone, or UTC when none is set.
  - `serverTime`: string (date-time), required. The server clock the view was computed at.
  - `study`: object or null, required. Flashcards, goal and streak. Null without `activity:view`.
    - `dueNow`: integer, required. Cards due now across every set.
    - `dueLaterToday`: integer, required. Cards that become due later in today's study day.
    - `newCards`: integer, required. Cards never studied.
    - `goal`: object, required
      - `kind`: one of `"cards"`, `"minutes"`, required. What the daily goal counts.
      - `target`: integer, required
      - `progress`: number, required. Cards answered or minutes studied.
      - `reached`: boolean, required
      - `streakDays`: integer, required. Days in a row the goal was reached.
      - `longestStreakDays`: integer, required
    - `limits`: object, required
      - `newRemaining`: integer, required. New cards the user may still start today.
      - `reviewsRemaining`: integer or null, required. Reviews left under the daily cap. Null when uncapped.
    - `studyDayEndsAt`: string (date-time), required. When today's study day ends (4am in the user's time zone) and the limits reset.
    - `subjects`: array of objects, required. Card counts per subject.
      - `subjectId`: string or null, required. Null for sets without a subject.
      - `name`: string, required
      - `dueNow`: integer, required
      - `overdue`: integer, required. Due before today's study day began.
      - `dueLaterToday`: integer, required
      - `newCards`: integer, required
    - `sets`: array of objects or null, required. The sets with the most cards due now, up to 10. Null without `sets:view`.
      - `setId`: string (uuid), required
      - `name`: string, required
      - `subjectId`: string or null, required. Subject id, when set.
      - `dueNow`: integer, required
  - `tasks`: object or null, required. Null without `tasks:view`.
    - `overdue`: array of objects, required. Unfinished tasks past due, oldest first, up to 5.
      - `id`: string (uuid), required
      - `name`: string, required
      - `type`: string, required
      - `subjectId`: string or null, required. Subject id, when set.
      - `subjectName`: string or null, required. The subject's name, when set.
      - `dueDate`: string (date-time) or null, required. Due date, when set.
      - `dueDay`: string or null, required. The due day (YYYY-MM-DD) in the user's time zone.
      - `exam`: boolean, required. True when the type or name reads like an exam, test or quiz.
    - `overdueTotal`: integer, required
    - `dueSoon`: array of objects, required. Unfinished tasks due today or in the next 6 days, up to 10.
      - `id`: string (uuid), required
      - `name`: string, required
      - `type`: string, required
      - `subjectId`: string or null, required. Subject id, when set.
      - `subjectName`: string or null, required. The subject's name, when set.
      - `dueDate`: string (date-time) or null, required. Due date, when set.
      - `dueDay`: string or null, required. The due day (YYYY-MM-DD) in the user's time zone.
      - `exam`: boolean, required. True when the type or name reads like an exam, test or quiz.
    - `dueSoonTotal`: integer, required
  - `lessons`: object or null, required. Today's lessons across active schedules. Null without `schedule:view`.
    - `occurrences`: array of objects, required
      - `scheduleId`: string (uuid), required
      - `date`: string, required. The day (YYYY-MM-DD).
      - `endDate`: string or null, required. The last day of an event that spans several days, or null.
      - `time`: one of the objects below, required. When the lesson runs, in the week's time zone.
        - One of `kind`: `"allDay"`
          - `kind`: `"allDay"`, required
        - Or `kind`: `"timed"`
          - `kind`: `"timed"`, required
          - `startMinute`: integer, required. Minutes after midnight.
          - `endMinute`: integer, required. Minutes after midnight.
        - Or `kind`: `"period"`
          - `kind`: `"period"`, required
          - `period`: integer, required. The period index. The period has no times.
          - `name`: string, required
      - `timeZone`: string or null, required. The event's own time zone, when an integration reports one.
      - `title`: string, required
      - `subtitle`: string or null, required. Room and teacher, when known.
    - `issues`: array of objects, required. External schedules that could not be read.
      - `scheduleId`: string (uuid), required
      - `issue`: one of `"unavailable"`, `"failed"`, `"timeout"`, required
  - `studyBlocks`: array of objects or null, required. Study blocks planned for today. Null without `schedule:view`.
    - `id`: string (uuid), required
    - `title`: string, required
    - `startsAt`: string (date-time), required. Start, in UTC.
    - `endsAt`: string (date-time), required. End, in UTC.
    - `date`: string, required. The day (YYYY-MM-DD) in the user's time zone.
    - `timeZone`: string, required. The time zone the block was planned in.
    - `subjectId`: string or null, required. The subject studied, when set.
    - `taskId`: string or null, required. The task worked on, when set.
    - `setId`: string or null, required. The study set practised, when set.
    - `createdAt`: string (date-time), required. Creation timestamp.
    - `updatedAt`: string (date-time), required. Last update timestamp.
  - `suggestions`: array of objects, required. What to do next, most useful first, built only from the sections this key may read.
    - `kind`: one of `"practice"`, `"learn"`, `"exam"`, `"overdue_task"`, `"lesson"`, `"plan"`, required. `practice`: flashcards are due. `learn`: nothing is due but new cards are left today. `exam`: an exam-like task is due within 7 days. `overdue_task`: an unfinished task is past due. `lesson`: the next lesson today. `plan`: nothing is planned today and tasks are due soon.
    - `message`: string, required. One sentence to show or say to the user.
    - `tool`: string or null, required. The operation (MCP tool) that acts on it, such as `startPracticeSession`. Only tools this key may call. Null when there is nothing to call.
    - `arguments`: any value, required. Arguments to pass to `tool`, as a JSON object. `{}` when it needs none.

### Example

```json
{
  "data": {
    "date": "2026-02-02",
    "timeZone": "Europe/London",
    "serverTime": "2026-02-02T08:15:00.000Z",
    "study": {
      "dueNow": 12,
      "dueLaterToday": 3,
      "newCards": 40,
      "goal": {
        "kind": "cards",
        "target": 20,
        "progress": 4,
        "reached": false,
        "streakDays": 6,
        "longestStreakDays": 14
      },
      "limits": {
        "newRemaining": 46,
        "reviewsRemaining": null
      },
      "studyDayEndsAt": "2026-02-03T04:00:00.000Z",
      "subjects": [
        {
          "subjectId": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
          "name": "Chemistry",
          "dueNow": 12,
          "overdue": 2,
          "dueLaterToday": 3,
          "newCards": 40
        }
      ],
      "sets": [
        {
          "setId": "7e6d5c4b-3a2f-4e1d-8c0b-9a8f7e6d5c4b",
          "name": "Spanish verbs",
          "subjectId": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
          "dueNow": 12
        }
      ]
    },
    "tasks": {
      "overdue": [],
      "overdueTotal": 0,
      "dueSoon": [
        {
          "id": "4d3c2b1a-0f9e-4d8c-9b7a-6f5e4d3c2b1a",
          "name": "Finish lab report",
          "type": "Generic",
          "subjectId": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
          "subjectName": "Chemistry",
          "dueDate": "2026-02-10T17:00:00.000Z",
          "dueDay": "2026-02-10",
          "exam": false
        }
      ],
      "dueSoonTotal": 1
    },
    "lessons": {
      "occurrences": [
        {
          "scheduleId": "4d3c2b1a-0f9e-4d8c-8b7a-6f5e4d3c2b1a",
          "date": "2026-02-02",
          "endDate": null,
          "time": {
            "kind": "timed",
            "startMinute": 540,
            "endMinute": 600
          },
          "timeZone": null,
          "title": "Biology",
          "subtitle": "S2 · Dr Patel"
        }
      ],
      "issues": []
    },
    "studyBlocks": [],
    "suggestions": [
      {
        "kind": "practice",
        "message": "12 flashcards are due now, most of them in Chemistry.",
        "tool": "startPracticeSession",
        "arguments": {
          "subjectId": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f"
        }
      },
      {
        "kind": "lesson",
        "message": "Next lesson: Biology at 09:00.",
        "tool": null,
        "arguments": {}
      }
    ]
  }
}
```

## 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`: No endpoint exists at this path.
- `405`: Method not allowed. Use a method from the Allow header.
- `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
