> ## Documentation Index
> Fetch the complete documentation index at: https://opentrain.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Project To-dos API

> HTTP reference for reading, previewing, and mutating the required job actions assigned to hired AI trainers.

The Project To-dos API reads and edits the same continuous list shown in a job's employer **Project To-dos** tab and in each AI trainer's manage-job view.

```text theme={null}
Base path: /api/public/v1/project-todos
```

## Endpoints

| Method | Path                            | Purpose                                                                                        |
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------- |
| `GET`  | `/project-todos`                | List the catalog, roster, assignments, and summary for a job or one contract.                  |
| `POST` | `/project-todos/manage`         | One discriminated `action` union for every preview and mutation.                               |
| `GET`  | `/project-todos/export-csv`     | Download per-person statuses as CSV (emails redacted).                                         |
| `GET`  | `/project-todos/quizzes/…`      | Quiz reads — see the [quiz surface](/docs/developers/api-reference/project-todos/quizzes/overview). |
| `POST` | `/project-todos/quizzes/manage` | Quiz authoring, assignment, grading, release, and retakes.                                     |

## Manage actions

`POST /project-todos/manage` dispatches on `action`:

| Action              | Purpose                                                                                                                |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `preflight`         | No-write preview and receipt mint for `create_item`, `update_item`, `assign`, or `archive_item`.                       |
| `set_enabled`       | Turn the job's Project To-dos surface on or off. Disabling requires active time-tracking integrations to be off first. |
| `create_category`   | Create a grouping category (idempotent per key).                                                                       |
| `create_item`       | Create one item and its initial assignments atomically.                                                                |
| `update_item`       | Publish a new immutable version, optionally reissuing it.                                                              |
| `archive_item`      | Retire an item; open assignments close with an audited reason.                                                         |
| `assign`            | Re-run assignment of the current version to a stated audience.                                                         |
| `worker_transition` | AI trainer actions: `VIEW`, `START`, `COMPLETE`, `SUBMIT`.                                                             |
| `review`            | Employer decisions: `APPROVE`, `RETURN`, `WAIVE`, `CLOSE`.                                                             |

## Authorization

List, export, and quiz reads require `project_todos:read`. Every `manage` action requires `project_todos:write` and a claimed account, plus employer access to the job (or, for `worker_transition`, ownership of the contract). The account must also have the default-off `project_todos_integrations` agent-surface family enabled. Scope failures return `403` with the missing resource named in `details`; a disabled family returns `403` with `details.reason = "AGENT_SURFACE_DISABLED"`.

## Write safety

* `audience` is required on every fan-out — omission is a `400`, never a broadcast. See the [concept page](/docs/developers/concepts/project-todos) for audience semantics.
* Broad audiences require a `preflightReceipt` from a matching `preflight` call.
* Every mutating action requires `idempotencyKey` (8–200 characters). Creation keys are bound to the complete request.
* Item creation, version publication, and assignment fan-out commit in one transaction.

## Common errors

| Status | `details.reason`                                                                                                     | Meaning                                                                                                                                                                                                                               |
| ------ | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | —                                                                                                                    | Validation failure; `SELECTED` offenders are listed in `details.invalidContractIds` with per-ID reasons (`UNKNOWN_CONTRACT`, `DIFFERENT_JOB`, `CONTRACT_ENDED`, `NO_ACTIVE_WORKER`) and duplicates in `details.duplicateContractIds`. |
| `409`  | `PROJECT_TODOS_DISABLED`                                                                                             | Enable Project To-dos in Job Settings first.                                                                                                                                                                                          |
| `409`  | `PREFLIGHT_RECEIPT_REQUIRED` / `PREFLIGHT_RECEIPT_INVALID` / `PREFLIGHT_RECEIPT_EXPIRED` / `PREFLIGHT_RECEIPT_STALE` | The broad-audience receipt is missing, unverifiable, past its \~15-minute life, or no longer matches the live roster or exact request (`details.changed` names what moved). Run `preflight` again.                                    |
| `409`  | `RECIPIENTS_CHANGED`                                                                                                 | The roster changed between confirmation and the write; `details` lists added and removed contract IDs. Preflight again.                                                                                                               |
| `409`  | `LIKELY_DUPLICATE`                                                                                                   | An active item with this exact request already exists (`details.duplicates`); pass `allowDuplicate: true` to create anyway.                                                                                                           |
| `409`  | —                                                                                                                    | An idempotency key was reused with a different request.                                                                                                                                                                               |

Use the machine-readable [OpenAPI document](https://app.opentrain.ai/api/public/v1/openapi.json) for complete schemas.
