# October 2026 v1 migration

> Update integrations written against the earlier v1 API.

Source: https://workroad.app/docs/api/v1-migration

## October 2026 changes to v1

This release changed v1 itself, because few integrations depended on it yet. It did not add `/api/v2`. Clients written against the earlier v1 need these updates:

- Reference fields are named `subjectId`, `parentId` and `termId`, and timestamps are `createdAt` and `updatedAt`. Path parameters have matching names such as `{taskId}` and `{setId}`; the URLs are the same.
- `cursor` takes only the opaque `nextCursor` value from a previous page. A row id is rejected with 400 `invalid_query`.
- Date fields accept only strings. A number or boolean returns 400 `invalid_request`.
- Unknown fields in a request body or query string return 400 that names the field. Before, they were ignored.
- An unknown or foreign `subjectId` on `POST /tasks` returns 400 `invalid_request`, where it was 404. A `folderId` on `POST /notes` that is not one of the user's folders also returns 400.
- A set, note or recording id in a request body that isn't the user's returns 400 `invalid_request` with `details.field` and `details.reason` (`unknown-set`, `unknown-note` or `unknown-recording`), not 404. This covers `sourceSetIds` and `sourceNoteIds` on `POST /tests`, `noteId` on `POST /sets/generate`, and a `start_generation` action that names a recording on `POST /copilot/messages/{messageId}/actions`. A 404 on those endpoints means the path's own resource is missing.
- Copilot messages page with `cursor` and `nextCursor`, not `before` and `nextBefore`. Conversations use the same opaque cursor.
- `GET /jobs/{jobId}` and `POST /jobs/{jobId}/cancel` check the job's kind against the key's scopes (see [Jobs](https://workroad.app/docs/api/copilot-and-generations#jobs)). A `copilot:use` key reads and cancels its copilot jobs and reads, applies and discards the generations they start. A `tests:view` or `files:view` key reads the jobs of its domain. A key with no scope for a kind gets 403.
- `POST /tests` requires a body `requestId` and creates no test when it is refused with 402 or 429. Before, a 402 left a `failed` test.
- Study set generation's `result` has `setId` and `termCount`, not `studySetId`.
- `insert-end` on a generation refuses a note that would pass 200,000 visible characters.
- Terms, definitions, hints and teacher names have length caps, listed under study sets and subjects.
- A task's `type` must be one of the user's task types; an unknown one returns 400 `unknown-task-type` unless the request sends `createType: true`. Before, any text was stored as the type.
- A task's `dueDate` or recurrence `endsAt` sent as `YYYY-MM-DD` is the start of that day in the user's time zone, not UTC midnight.
