Learning Studio / agents
Use the HTTP agent API
Read courses, apply operations, and inspect history through authenticated requests.
Use the HTTP API to read courses, propose changes, and inspect saved versions. Start with discovery so your integration uses the available endpoints and schemas.
Base path
Section titled “Base path”Use your app origin plus /api/public/agent, and send a user access token with every request. Send GET to the 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, design, and build; their inputs differ. Check the schema for the action you need; an edit instruction is not a valid body for every action. MCP exposes the same rewrite, wrong-answer, design, comment, assessment-plan and alignment-CSV work as its own tools. Level suggestions, rubric drafts and the decision log are MCP tools as well.
Read alignment
Section titled “Read alignment”GET /courses/:id/alignment returns version, blueprint, alignment, strength, assessmentBlueprint, and timeEstimates. The strength array has one entry per objective × scored-question link. Each entry includes objectiveId, questionId, blockId, sectionId, and strength (aligned, below_level, kind_too_weak, or unclassified). When a framework drove the result, the entry also includes frameworkId, objectiveLevelId, and questionLevelId; when the question type limited rigor, ceilingLevelId. An author acceptance adds overrideReason and the link counts as aligned. To accept a question, send block.update with the question’s rigorOverride: { reason } (1–200 characters); leave it out to remove the acceptance.
assessmentBlueprint summarizes scored questions linked to at least one objective: frameworkId, levels, totalPoints, unlinkedPoints, unlinkedQuestions, objectives (each with objectiveId, points, percent, questionCount, optional targetPercent, optional difference), levelTotals, cells, and deviations (each with id blueprint_weight_deviation, objectiveId, actualPercent, targetPercent, difference). Practice questions and scored questions with no objective link are excluded from totalPoints.
Add ?format=csv to get the alignment as CSV instead: one row per objective × linked element, with columns objective_code, objective_text, objective_revision, objective_status, element_kind, element_id, page_title, tier, strength, level and points (UTF-8 with a byte order mark, RFC 4180 quoting). The JSON response also includes timeEstimates (courseMinutes, estimatedPages, totalPages, perObjective); set a page’s estimate with section.update and estimatedMinutes (1–600, or null to clear).
Set or clear targets with course.settings.update and assessmentTargets: an array of { objectiveId, weightPercent } entries (each 0–100; the sum must be at most 100), or null or [] to clear all targets.
Dry-run example
Section titled “Dry-run example”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.
Create and version a course
Section titled “Create and version a course”POST /courses to create a course. For a blank course, send idempotencyKey (8–100 characters), optional title (1–200 characters), and optional language (up to 16 characters; default en). A new blank course returns 201; a replay with the same key returns 200.
To generate initial content with AI, also supply ai: { mode, text }. Use mode prompt for a short brief or mode document for source text. Text is limited to 60,000 characters; document mode requires at least 200 characters, and prompt mode requires at least 20. The AI creates the course and commits the draft as one version. The AI creation branch currently does not replay the supplied idempotency key, so if the response is interrupted, check the course list before retrying to avoid creating a second 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. Check each operation’s retry behavior; the /ops replay guarantee doesn’t apply to every endpoint.
After a successful response, open Studio home to find the course. The fixture image below illustrates where courses appear; it is not a capture of an HTTP request or proof of API creation.
AI request bodies
Section titled “AI request bodies”| 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) |
design |
baseVersion ≥1, brief (10–20,000), approach (academic or performance) |
audience (customers or employees) |
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. A design brief is 10–20,000 characters on both. Edit, blueprint, design, and build return operations as suggestions; apply them separately through /ops. design returns course.settings.update (objectives) and course.design.update (the Backward Design plan), plus model, rationale, sources, promptVersion, and eventId. Nothing is saved. audience applies only when approach is performance; omit it to use the course audience, or customers when the course has none. Academic ignores audience. Rewrite returns text, and distractors returns options. A stale AI base version can return 409; provider failures can return 502.
Files and comments
Section titled “Files and comments”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.