DEVELOPER DOCUMENTATION
Individualized retraining API
REST endpoints for draft retraining cases, no-write assignment plans, exact-one assignment, live reporting, and reusable skill-gap modules.
The retraining API orchestrates existing LMS and Project To-do operations for one worker. It does not create a second course, assignment, grading, or retry system.
Base path: /api/public/v1/lms/retrainingDiscover capabilities first
Section titled “Discover capabilities first”Read rollout and authorization before the scoped LMS schema:
curl -sS https://app.opentrain.ai/api/public/v1/capabilities \ -H "Authorization: Bearer $OT_API_TOKEN"Inspect the LMS retraining family under agentSurfaces: the family status is disabled, rollout_gated, unauthorized, or available, and each operation has its own authorized value. Treat every status except available as fail-closed.
Then read the canonical LMS contract before composing requests:
curl -sS https://app.opentrain.ai/api/public/v1/lms/capabilities \ -H "Authorization: Bearer $OT_API_TOKEN"Inspect capabilities.retraining for operations, modes, exact-one recipient and due-date rules, plan receipt bindings, receipt lifetime, close outcomes, and human checkpoints. The same response describes current course, lesson, assessment, asset, Preview, and mastery capabilities.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
POST | /cases | Create one employer-only DRAFT case. |
GET | /cases | List cases with bounded cursor pagination. |
GET | /cases/{caseId} | Read a case plus live assignment, review, and bounded run projections. |
PATCH | /cases/{caseId} | Update a draft under expectedStateRevision. |
POST | /cases/{caseId}/plan | Produce a signed, strictly no-write assignment plan. |
POST | /cases/{caseId}/scaffold | Produce deterministic, strictly no-write authoring guidance. |
POST | /cases/{caseId}/assign | Confirm the reviewed plan and create one Project To-do assignment atomically. |
POST | /cases/{caseId}/close | Close the case with an outcome that agrees with canonical assignment state. |
GET | /modules | List reusable published skill-gap modules with bounded cursor pagination. |
POST | /modules | Register or relabel a published course module. |
Authorization
Section titled “Authorization”Reads require lms:read. Writes and the protected no-write plan require lms:write. Every operation enforces organization and job access. Worker names are masked. Answer keys, correct values, and other workers’ submissions are never included.
Create, update, assign, close, and module-registration requests require an Idempotency-Key header. Replaying the same key with the same request returns the stored result. Reusing it with a different request fails with 409 CONFLICT. Planning intentionally takes no idempotency key because it performs no writes.
Create a case
Section titled “Create a case”POST /cases requires an Idempotency-Key header and an exact-one worker reference:
{ "jobId": "job-id", "worker": { "contractId": "contract-id" }, "observedMistake": "The submitted reconciliation omitted the cutoff check.", "expectedBehavior": "Reconcile the full population and document the cutoff test before submission.", "workerSummary": "Review the reconciliation and cutoff workflow", "mode": "MASTERY", "courseId": "course-id", "moduleKey": "reconciliation-cutoff", "masteryRunLimit": 3, "dueOffsetMinutes": 1440, "priority": "URGENT", "required": true, "blockingMode": "IMMEDIATE", "instructionRefs": ["instruction-page-id"]}Use either worker.contractId or worker.workerName, never both. Exact-name resolution fails closed on zero or multiple matches.
Use exactly one of dueOffsetMinutes or absoluteDue:
{ "absoluteDue": { "localDate": "2026-09-01", "localTime": "17:00", "timeZone": "America/New_York" }}Update a draft
Section titled “Update a draft”PATCH /cases/{caseId} requires expectedStateRevision and an Idempotency-Key header:
{ "expectedStateRevision": 2, "patch": { "courseId": "course-id", "moduleKey": "reconciliation-cutoff" }}The operation updates only a DRAFT case. A stale revision returns 409 CONFLICT; read the current case before deciding whether to retry.
Scaffold the canonical course
Section titled “Scaffold the canonical course”POST /cases/{caseId}/scaffold requires lms:write, but performs no writes and
takes no idempotency key. The response binds the guidance to the case’s current
stateRevision and captureHash, then returns:
- employer-only grounding and a deterministic lesson outline;
authoringIntentfor the canonical LMS draft;- mastery constraints, including at least one required auto-graded question and no manual questions;
- ordered
nextActionsthat reference registered operations such aslms.courses.manageandlms.assessments.manage; and - zero side-effect counters for writes, notifications, and attempts.
The draft-level intent uses this shape:
{ "schemaVersion": 1, "validationIntent": "INDIVIDUAL_MASTERY", "completionPolicy": "SYSTEM"}INDIVIDUAL_MASTERY requires SYSTEM. The API returns
400 AUTHORING_CONTRADICTION for incompatible intent instead of silently
changing the course. Standard employer-reviewed retraining uses STANDARD +
EMPLOYER_REVIEW. The intent is advisory authoring metadata; the published
version and assignment remain authoritative for learner delivery.
Plan and assign
Section titled “Plan and assign”POST /cases/{caseId}/plan takes no idempotency key and performs no writes. The response includes:
- the masked recipient and stable contract ID;
- the exact published course version, module, and content hash;
- the case revision and capture hash;
- the exact frozen due instant;
- mastery eligibility and warnings;
- zero plan-side writes, notifications, and attempts;
- the exact confirmation effects;
- a request hash and short-lived signed receipt.
An authorized employer must review and explicitly approve the exact masked recipient, version and content hash, frozen due instant, effects, request hash, and receipt before assignment.
After that approval, confirm with POST /cases/{caseId}/assign, an Idempotency-Key header, and:
{ "expectedStateRevision": 2, "planReceiptToken": "signed-plan-token", "confirmAssign": true}confirmAssign: true records the approved mutation; it does not authorize an agent to approve its own plan. The receipt becomes stale when the captured case, course content, course version, or revision changes. Re-plan and obtain approval for the new result instead of forcing a stale assignment.
Read and close
Section titled “Read and close”GET /cases/{caseId} returns employer-safe case details plus live projections from the canonical assignment and review readers. Run history is bounded; follow the returned cursor through the canonical LMS run-history operation when more rows exist.
GET /cases and GET /modules return hasMore and an opaque nextCursor. Pass nextCursor back unchanged as cursor and continue until hasMore === false before reporting a complete inventory. A cursor outside the authorized, filtered result set returns 400 BAD_REQUEST.
Closing is terminal for that occurrence. PASSED requires a canonically completed assignment. FAILED requires an exhausted failure parked with the employer. CANCELLED and SUPERSEDED do not cancel an active assignment; resolve that assignment through its canonical operation first.
POST /cases/{caseId}/close requires an Idempotency-Key header and:
{ "expectedStateRevision": 4, "outcome": "PASSED", "reason": "Completed the assigned remediation", "confirmClose": true}Errors
Section titled “Errors”Failures use the shared envelope:
{ "error": "Human-readable message", "code": "CONFLICT", "requestId": "request-id", "details": { "reason": "machine-readable-context" }}Branch on code and structured details, not error. Common retraining statuses are: create 404/409/422, update 409/422, plan 404/409/422, assign 409, close 409, and list 400. See Errors, Pagination, and Rate Limits for the shared meanings and retry rules.
Register a reusable module
Section titled “Register a reusable module”POST /modules takes an Idempotency-Key header:
{ "courseId": "course-id", "moduleKey": "reconciliation-cutoff", "label": "Reconciliation and cutoff", "description": "Targeted remediation for reconciliation completeness and period cutoff."}The module must exist in the course’s current published version. Registration stores reusable metadata only; it does not edit the course.
Use the machine-readable OpenAPI document for the complete request and response schemas.