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

# Assign a Quiz

> Preview and create a quiz Project To-do pinned to one immutable published form version.

Assigning a quiz is a fan-out, so it carries the full [audience safety contract](/docs/developers/concepts/project-todos): an explicit `audience`, strict `SELECTED` validation, and a signed preflight receipt for broad audiences. The server computes all binding hashes itself — you never hand-craft them. Requires `project_todos:write` and employer access to the job.

## `quiz_todo_preflight`

A no-write preview of the exact assignment. It mirrors every live gate: the job must have Project To-dos enabled, the version must be published, and `ON_PASS` requires a pass rule and no manually graded questions — a live-invalid request fails the preflight and returns no receipt.

<ParamField body="action" type="string" required>`quiz_todo_preflight`</ParamField>

<ParamField body="jobId" type="string" required />

<ParamField body="formVersionId" type="string" required>The immutable published version to pin.</ParamField>
<ParamField body="completionPolicy" type="string" required>`ON_SUBMIT`, `ON_PASS`, or `ON_REVIEW`.</ParamField>
<ParamField body="audience" type="string" required>No default; `SELECTED` requires exact same-job active `selectedContractIds`.</ParamField>
<ParamField body="title" type="string">Optional override; defaults to the form title.</ParamField>

<ParamField body="description" type="string" />

<ParamField body="required" type="boolean" />

<ParamField body="priority" type="string" />

<ParamField body="blockingMode" type="string" />

<ParamField body="dueOffsetMinutes" type="number" />

The `preflight` response includes the exact job and form version, the live masked recipients and count, future-hire semantics, projected due and blocking behavior, `duplicates.sameFormVersion` (active to-dos already pinning this exact version), warnings, and — for broad audiences — the `receipt` to pass back.

## `quiz_todo_create`

Creates the item and every initial assignment atomically. Send the identical payload plus:

<ParamField body="idempotencyKey" type="string" required>
  A stable key; retries of the identical request converge and never widen the original fan-out.
</ParamField>

<ParamField body="preflightReceipt" type="string">Required for `ACTIVE`, `FUTURE`, and `ACTIVE_AND_FUTURE`.</ParamField>
<ParamField body="allowDuplicate" type="boolean">Overrides the exact-duplicate refusal.</ParamField>

## Normalized result

```json theme={null}
{
  "ok": true,
  "action": "quiz_todo_create",
  "itemId": "…",
  "versionId": "…",
  "audience": "ACTIVE",
  "includesFutureHires": false,
  "fanOut": {
    "matchedContracts": 2,
    "createdAssignments": 2,
    "skippedExistingAssignments": 0,
    "failedAssignments": 0,
    "assignmentIds": ["…", "…"]
  },
  "recipients": [{ "contractId": "…", "displayName": "Alex B." }],
  "replayed": false,
  "warnings": []
}
```

`failedAssignments` is always `0` on success: the transaction cannot commit a partial fan-out. `skippedExistingAssignments` counts recipients who already held this operation's assignment on a convergent retry. Assigned quizzes are immediately visible to the AI trainers they target.
