Skip to content

Learning Studio / agents

Use the HTTP agent API

Read courses, apply operations, and inspect history through authenticated requests.

Use your app origin plus /api/public/agent. Send a user access token with every request. Start with GET on that base path to inspect discovery.

Method Path after the base Purpose
GET / POST /courses List / create a course
GET /courses/:id Read content and version
POST /courses/:id/ops Validate or apply operations
GET / POST /courses/:id/versions List versions / save a checkpoint
GET /courses/:id/versions/:versionId Read a saved version
POST /courses/:id/files Upload multipart field file
GET / POST /courses/:id/comments Read threads / add feedback or update a thread
GET /courses/:id/alignment Read objective alignment
POST /courses/:id/ai/:action Request an AI suggestion

AI actions include edit, rewrite, distractors, blueprint, and build; their inputs differ. Use the route-specific schema rather than sending an edit instruction to every action.

Replace the ID and base version with values from a fresh course read. Send this JSON to POST /courses/:id/ops:

{
"baseVersion": 1,
"idempotencyKey": "example-title-update-001",
"dryRun": true,
"label": "Clarify course title",
"ops": [
{ "op": "course.settings.update", "patch": { "title": "Designing meaningful learning" } }
]
}

A dry run validates without saving. To commit after review, submit with dryRun: false and the still-current version. See operations and recovery for conflicts and retries.

For a blank course, POST /courses with idempotencyKey, optional title (1–200 characters), and optional language (up to 16; default en). A new blank course returns 201; a replay returns 200.

To request an AI draft, also supply ai: { mode, text }, with mode prompt or document. Text is limited to 60,000 characters; document mode needs at least 200. The AI creation branch currently does not replay the supplied idempotency key. Check the course list after an interrupted response before retrying, to avoid creating another draft.

List versions with GET /courses/:id/versions; use its before cursor for older entries. POST the same path with { "label": "Before restructuring" } to save a checkpoint. GET /courses/:id/versions/:versionId returns content for a saved version. These operations do not all share the /ops retry contract.

Action Required fields Optional fields
edit baseVersion ≥1, instruction (3–2,000) scopeBlockId, scopeSectionId (up to 100 each)
rewrite text (1–8,000), instruction (3–1,000) context (up to 8,000; default empty)
distractors prompt (1–500), correct (1–6 strings up to 300), count (1–5) None
blueprint baseVersion ≥1, brief (10–20,000) length (short, medium, long; default medium)
build baseVersion ≥1 None

For edit, supply a scopeSectionId for a content page or a scopeBlockId on that page. Although both fields are optional in the request schema, the current runtime requires at least one: requests without a page scope, or targeting a cover/chapter, return 422. If both are supplied they must identify the same page. An edit suggestion is limited to that page; it is not a whole-course rewrite.

The HTTP blueprint brief limit differs from MCP’s 4,000-character limit. Edit, blueprint, and build return operations as suggestions; apply them separately through /ops. Rewrite returns text, and distractors returns options. A stale AI base version can return 409; provider failures can return 502.

Upload files to /courses/:id/files using multipart form field file, with the user bearer token. The current upload limit is 200 MB; an oversized request returns 413. The HTTP upload route remains course-scoped; the account Files library and its version controls are UI workflows, not additional public agent endpoints. Use its returned resource/storage path in the appropriate content operation; do not store a temporary signed URL as a permanent media reference.

GET /courses/:id/comments?status=open or status=resolved filters threads. POST accepts these alternative bodies:

{ "sectionId": "page-1", "blockId": "intro-1", "body": "Could this include a worked example?" }
{ "threadId": "<thread ID from the response>", "body": "The example is now included." }
{ "threadId": "<thread ID from the response>", "status": "resolved" }

Comment access follows owner/reviewer permissions. Comment bodies are limited to 4,000 characters. Comment creation does not take an idempotency key, so inspect existing threads before retrying an uncertain creation response.