# Subjects

> Create, rename, archive and delete the subjects that tie a user's work together.

Source: https://workroad.app/docs/api/subjects

## How subjects work

A subject tags the tasks, notes, study sets and schedule elements the key's user owns. A subject has at most 20 teachers, each up to 120 characters. `DELETE /subjects/{subjectId}` unfiles it from all of those, then deletes it. It leaves timetable elements on schedules the key's user doesn't own untouched, even when those schedules reference the same subject.

Name the subject with `subjectId`, or with `subjectName`, which must match one of the user's active subjects ignoring case and accents. A name that matches none returns 400 with `details.reason` `unknown-subject` and the user's subjects in `details.subjects`. Send `createSubjectIfMissing: true` to create it, which also needs `subjects:create`. Tasks, study sets and note folders all take `subjectName`.

## Get a subject

`GET https://workroad.app/api/v1/subjects/{subjectId}`

Returns one subject the key's user owns.

- MCP tool: `getSubject` on `https://workroad.app/api/mcp`
- Required scopes: subjects:view or tasks:view or schedule:view or notes:view or sets:view
- Test mode: `GET https://workroad.app/api/test/v1/subjects/{subjectId}` checks the request and returns the example response without changing anything.

### Path parameters

- `subjectId`: string (uuid), required. Subject id, scoped to the key's user.

### Response

`200` OK

- `data`: object, required
  - `id`: string (uuid), required
  - `name`: string, required
  - `teachers`: array of string, required
  - `period`: string or null, required. Free-text term or year label, or null.
  - `archived`: boolean, required. An archived subject keeps everything filed under it but is not offered for new items.

#### Example

```json
{
  "data": {
    "id": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
    "name": "Chemistry",
    "teachers": [
      "Dr. Curie"
    ],
    "period": "Year 12",
    "archived": false
  }
}
```

### Errors

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

- `400`: Invalid request body or query
- `401`: Missing, invalid, disabled or expired API key
- `402`: `api_allowance_reached`: this month's API and AI app requests on the free plan are used up. `details` has `limit`, `used`, `resetsAt` and `upgradeUrl`. Nothing ran; WorkRoad Plus has no monthly limit.
- `403`: The API key lacks the required scope
- `404`: No subject with that id exists for this key's user.
- `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

## List subjects

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

Returns every subject the user owns. Subjects are few and carry no creation timestamp, so this endpoint is not paginated.

- MCP tool: `listSubjects` on `https://workroad.app/api/mcp`
- Required scopes: subjects:view or tasks:view or schedule:view or notes:view or sets:view
- Test mode: `GET https://workroad.app/api/test/v1/subjects` checks the request and returns the example response without changing anything.

### Response

`200` OK

- `data`: array of objects, required
  - `id`: string (uuid), required
  - `name`: string, required
  - `teachers`: array of string, required
  - `period`: string or null, required. Free-text term or year label, or null.
  - `archived`: boolean, required. An archived subject keeps everything filed under it but is not offered for new items.

#### Example

```json
{
  "data": [
    {
      "id": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
      "name": "Chemistry",
      "teachers": [
        "Dr. Curie"
      ],
      "period": "Year 12",
      "archived": false
    }
  ]
}
```

### Errors

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

- `400`: Invalid request body or query
- `401`: Missing, invalid, disabled or expired API key
- `402`: `api_allowance_reached`: this month's API and AI app requests on the free plan are used up. `details` has `limit`, `used`, `resetsAt` and `upgradeUrl`. Nothing ran; WorkRoad Plus has no monthly limit.
- `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

## Create a subject

`POST https://workroad.app/api/v1/subjects`

Fails on a name already in active use.

- MCP tool: `createSubject` on `https://workroad.app/api/mcp`
- Required scopes: subjects:create
- Test mode: `POST https://workroad.app/api/test/v1/subjects` checks the request and returns the example response without changing anything.
- Next: file tasks, study sets, note folders and lessons under it by passing its `id` as `subjectId`.

### 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.

- `name`: string, required, 1-64 characters
- `teachers`: array of string, up to 20 items, default `[]`. Teacher names, in no particular order.
- `period`: string or null, up to 60 characters. Free-text term or year label, e.g. `Year 12`. `null` clears it.

### Response

`201` Created

- `data`: object, required
  - `id`: string (uuid), required
  - `name`: string, required
  - `teachers`: array of string, required
  - `period`: string or null, required. Free-text term or year label, or null.
  - `archived`: boolean, required. An archived subject keeps everything filed under it but is not offered for new items.

#### Example

```json
{
  "data": {
    "id": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
    "name": "Chemistry",
    "teachers": [
      "Dr. Curie"
    ],
    "period": "Year 12",
    "archived": false
  }
}
```

### Errors

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

- `400`: Invalid body, or the name is already in active use.
- `401`: Missing, invalid, disabled or expired API key
- `402`: `api_allowance_reached`: this month's API and AI app requests on the free plan are used up. `details` has `limit`, `used`, `resetsAt` and `upgradeUrl`. Nothing ran; WorkRoad Plus has no monthly limit.
- `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.
- `409`: 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

## Update a subject

`PATCH https://workroad.app/api/v1/subjects/{subjectId}`

Changes only the fields you send. `archived` and any name, teachers or period change are checked and written together, against the subject's final state. Archiving a subject whose course is over also archives its active study sets, so they leave reviews and practice; restoring the subject restores exactly those. `setsArchived` and `setsRestored` count them.

- MCP tool: `updateSubject` on `https://workroad.app/api/mcp`
- Required scopes: subjects:update
- Test mode: `PATCH https://workroad.app/api/test/v1/subjects/{subjectId}` checks the request and returns the example response without changing anything.

### Path parameters

- `subjectId`: string (uuid), required. Subject id, scoped to the key's user.

### Request body

JSON.

- `name`: string, 1-64 characters
- `teachers`: array of string, up to 20 items. Replaces the full list when sent.
- `period`: string or null, up to 60 characters. Free-text term or year label, e.g. `Year 12`. `null` clears it.
- `archived`: boolean. Archives or restores the subject. Checked and written together with the other fields, against the subject's final state. Archiving it also archives its active study sets, which takes them out of reviews and practice; restoring it restores exactly those, not a set archived on its own.

### Response

`200` OK

- `data`: object, required
  - `id`: string (uuid), required
  - `name`: string, required
  - `teachers`: array of string, required
  - `period`: string or null, required. Free-text term or year label, or null.
  - `archived`: boolean, required. An archived subject keeps everything filed under it but is not offered for new items.
  - `setsArchived`: integer, required. Study sets this request archived with the subject.
  - `setsRestored`: integer, required. Study sets this request restored with the subject.

#### Example

```json
{
  "data": {
    "id": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
    "name": "Chemistry",
    "teachers": [
      "Dr. Curie"
    ],
    "period": "Year 12",
    "archived": false,
    "setsArchived": 0,
    "setsRestored": 0
  }
}
```

### Errors

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

- `400`: Invalid body, no field to update, or the name is already in active use.
- `401`: Missing, invalid, disabled or expired API key
- `402`: `api_allowance_reached`: this month's API and AI app requests on the free plan are used up. `details` has `limit`, `used`, `resetsAt` and `upgradeUrl`. Nothing ran; WorkRoad Plus has no monthly limit.
- `403`: The API key lacks the required scope
- `404`: No subject with that id exists for this key's user.
- `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

## Delete a subject

`DELETE https://workroad.app/api/v1/subjects/{subjectId}`

Unfiles the subject from every task, note folder, study set and schedule element the key's user owns, then deletes it. Never touches another user's timetable.

- MCP tool: `deleteSubject` on `https://workroad.app/api/mcp`
- Required scopes: subjects:delete
- Test mode: `DELETE https://workroad.app/api/test/v1/subjects/{subjectId}` checks the request and returns the example response without changing anything.

### Path parameters

- `subjectId`: string (uuid), required. Subject id, scoped to the key's user.

### Response

`200` OK

- `data`: object, required
  - `id`: string (uuid), required
  - `deleted`: `true`, required

#### Example

```json
{
  "data": {
    "id": "5f0c1d2e-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
    "deleted": true
  }
}
```

### Errors

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

- `400`: Invalid request body or query
- `401`: Missing, invalid, disabled or expired API key
- `402`: `api_allowance_reached`: this month's API and AI app requests on the free plan are used up. `details` has `limit`, `used`, `resetsAt` and `upgradeUrl`. Nothing ran; WorkRoad Plus has no monthly limit.
- `403`: The API key lacks the required scope
- `404`: No subject with that id exists for this key's user.
- `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
