Create Course

Generate an AI-powered course curriculum from a prompt and receive edit/preview URLs.

POST /v1/platform/courses

Creates a course request. The AI model generates a structured curriculum with chapters and lessons, creates the course in TutorFlow, and returns edit and preview URLs.

Tiers

The tier field selects the quality and pricing contract for the request. If omitted, TutorFlow defaults to standard:

TierPrice
basic$0.09
standard$0.19
advanced$0.29

TutorFlow stores a price snapshot at request time so billing remains consistent even if pricing is updated later.

Lesson Types

The AI selects interactive lesson types based on the course topic:

TypeDescriptionBest for
ai-tutorInteractive AI tutor that discusses concepts with the studentMath, science, conceptual topics
coding-lessonHands-on coding tutorial with IDEProgramming topics only
coding-testCoding exercise/challengeProgramming practice only
chat-aiAI conversation lessonPrompt engineering, AI topics
examQuiz/assessmentPractice problems, end-of-chapter review
flashcardReview/vocabulary/formula cardsLanguage learning, key concepts
markdownText-only readingCourse overview, reference material

The coding-lesson and coding-test types are reserved for programming topics. For math, science, language, or general-knowledge courses, the AI uses ai-tutor, chat-ai, exam, flashcard, or markdown instead.

The first lesson of every course is generated as ai-tutor so the learner has an interactive entry point regardless of subject.

Request Body

FieldTypeRequiredDescription
promptstringYesPrompt describing the course to generate
titlestringNoOverride AI-generated title
descriptionstringNoOverride AI-generated description
languagestringNoCourse language (default: en)
levelstringNobeginner, intermediate, or advanced (validated enum)
subjectstringNoSubject area (e.g. mathematics, physics, programming)
lessonCountnumberNoTarget number of lessons for AI to generate (1–50)
classroomIdstringNoClassroom ID to create the course in. Uses the default classroom if omitted
tierstringNobasic, standard, or advanced. Defaults to standard
hasQuizbooleanNoWhether to include quiz lessons in the generated course
hasPracticebooleanNoWhether to include practice exercises in the generated course
idempotencyKeystringNoPrevents duplicate processing. Can also be sent via Idempotency-Key HTTP header
modestringNosync (default) or async

Example Request

curl -X POST https://api.tutorflow.io/v1/platform/courses \
  -H "Authorization: Bearer tf_platform_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Create a beginner Python course covering variables, loops, and functions with hands-on exercises",
    "language": "en",
    "level": "beginner",
    "lessonCount": 5
  }'

Response Fields

FieldTypeDescription
idstringPlatform course request ID
statusstringPENDING, PROCESSING, COMPLETED, or FAILED
courseIdstring | nullActual course ID in TutorFlow (null until generation completes)
titlestring | nullCourse title
descriptionstring | nullCourse description
levelstring | nullDifficulty level
languagestring | nullCourse language (echoed from request, e.g. en)
subjectstring | nullSubject area (echoed from request)
slugstring | nullURL-friendly course slug
tierstringPricing tier used
modestring | nullExecution mode (sync or async)
hasQuizboolean | nullWhether quizzes were requested
hasPracticeboolean | nullWhether practice exercises were requested
lessonCountnumber | nullNumber of lessons in the generated course (length of lessons). Null until generation completes.
priceSnapshotobject | nullPricing details captured at request time
chaptersarray | nullChapter summaries with title, sequence, lessonCount, and slug
lessonsarray | nullLesson summaries with title, type, sequence, chapterTitle, chapterSlug, lessonSlug, and lessonUrl
shareTokenstring | nullToken used to construct the public URL and to resolve edit tokens for the list-mode preview link
previewUrlstring | nullEditor URL — direct link to /{locale}/platform/courses/edit/{editToken} (single-course endpoints) or /{locale}/platform/courses/{shareToken} (list endpoint, auto-resolves the latest edit token)
publicUrlstring | nullPublic read-only learner URL, opens at the first lesson
isTerminalbooleanWhether the request has reached a final state
pollAfterMsnumber | nullRecommended polling interval for async requests
idempotencyKeystring | nullEchoed idempotency key
idempotentReplayboolean | nulltrue if this response reused an existing request, false for a fresh request, null when no idempotencyKey was provided
createdAtstringISO 8601 timestamp
completedAtstring | nullISO 8601 timestamp when generation completed

Example Response

{
  "id": "a1c2d3e4-f5g6-7h8i-9j0k-l1m2n3o4p5q6",
  "status": "COMPLETED",
  "courseId": "c7d8e9f0-1a2b-3c4d-5e6f-7g8h9i0j1k2l",
  "title": "Python Quick Start",
  "description": "A beginner-friendly Python course covering variables, loops, and functions.",
  "language": "en",
  "subject": null,
  "level": "beginner",
  "slug": "python-quick-start-2e5ad6",
  "tier": "standard",
  "mode": "sync",
  "hasQuiz": true,
  "hasPractice": true,
  "lessonCount": 6,
  "priceSnapshot": {
    "category": "course",
    "catalogKey": "course.standard",
    "tier": "standard",
    "amountUsd": 0.19,
    "unit": "course",
    "currency": "USD",
    "source": "platform_pricing_catalog_v1"
  },
  "shareToken": "b018172542f9a3c4d5e6f7890abcdef12345678",
  "previewUrl": "https://tutorflow.io/en/platform/courses/edit/9f3a...",
  "publicUrl": "https://tutorflow.io/en/platform/courses/b018172542f9.../lessons/1",
  "chapters": [
    { "title": "Introduction to Variables", "sequence": 1, "lessonCount": 2, "slug": "introduction-to-variables-cf1710" },
    { "title": "Working with Loops", "sequence": 2, "lessonCount": 2, "slug": "working-with-loops-253716" },
    { "title": "Defining Functions", "sequence": 3, "lessonCount": 2, "slug": "defining-functions-ad2b35" }
  ],
  "lessons": [
    { "title": "Welcome to Python", "type": "ai-tutor", "sequence": 1, "chapterTitle": "Introduction to Variables", "chapterSlug": "introduction-to-variables-cf1710", "lessonSlug": "welcome-to-python-29ae64", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/1" },
    { "title": "Variable Practice", "type": "coding-test", "sequence": 2, "chapterTitle": "Introduction to Variables", "chapterSlug": "introduction-to-variables-cf1710", "lessonSlug": "variable-practice-1b3f82", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/2" },
    { "title": "For and While Loops", "type": "coding-lesson", "sequence": 3, "chapterTitle": "Working with Loops", "chapterSlug": "working-with-loops-253716", "lessonSlug": "for-and-while-loops-59c305", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/3" },
    { "title": "Loop Challenges", "type": "coding-test", "sequence": 4, "chapterTitle": "Working with Loops", "chapterSlug": "working-with-loops-253716", "lessonSlug": "loop-challenges-a4b5c6", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/4" },
    { "title": "Writing Functions", "type": "coding-lesson", "sequence": 5, "chapterTitle": "Defining Functions", "chapterSlug": "defining-functions-ad2b35", "lessonSlug": "writing-functions-d7e8f9", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/5" },
    { "title": "Function Exercises", "type": "coding-test", "sequence": 6, "chapterTitle": "Defining Functions", "chapterSlug": "defining-functions-ad2b35", "lessonSlug": "function-exercises-0a1b2c", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/6" }
  ],
  "idempotencyKey": null,
  "idempotentReplay": null,
  "isTerminal": true,
  "createdAt": "2026-03-24T10:32:15.108Z",
  "completedAt": "2026-03-24T10:32:37.671Z"
}

Preview URL vs Public URL

URLPurposeAuthExpiry
previewUrlCourse editor (lecture, title, curriculum, chapters, lessons)Public, no loginEdit token expires after 1h
publicUrlPublic course URL for learners, opens at the first lessonPublic, no loginNone

The previewUrl returned by POST /v1/platform/courses and GET /v1/platform/courses/:id is a direct link to the editor for the current edit token (/{locale}/platform/courses/edit/{editToken}). Anyone with the URL can edit lesson content, title, description, and curriculum structure without logging in. The edit token is valid for one hour; the share-token endpoints (GET /public/:shareToken/full) auto-refresh it on access, or you can mint a new one explicitly via POST /v1/platform/courses/:id/edit-token.

The list endpoint (GET /v1/platform/courses) returns a previewUrl of the form /{locale}/platform/courses/{shareToken} instead — that page resolves the latest edit token server-side and redirects into the editor, so you do not need to refresh tokens before generating list links.

The publicUrl is the read-only link you share with learners. Each lesson summary also includes a lessonUrl that links directly to that lesson by sequence.

Refreshing an Edit Token

curl -X POST https://api.tutorflow.io/v1/platform/courses/a1c2d3e4.../edit-token \
  -H "Authorization: Bearer tf_platform_..."
{
  "editToken": "new-token-hex...",
  "editTokenExpiresAt": "2026-03-24T13:30:00.000Z"
}

Edit Token API

The edit URL provides access to these public endpoints (no API key needed):

MethodPathDescription
GET/v1/platform/courses/edit/:editTokenGet course summary
GET/v1/platform/courses/edit/:editToken/fullGet full course with all lesson content
GET/v1/platform/courses/edit/:editToken/lessons/:sequenceGet single lesson
PATCH/v1/platform/courses/edit/:editTokenUpdate course title/description
PATCH/v1/platform/courses/edit/:editToken/lessons/:sequenceUpdate lesson content, title, slug, or description
POST/v1/platform/courses/edit/:editToken/lessonsAdd a new lesson to the course
POST/v1/platform/courses/edit/:editToken/infer-typeInfer the best lesson type from a title/description

Add Lesson

curl -X POST https://api.tutorflow.io/v1/platform/courses/edit/{editToken}/lessons \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Solving Quadratic Equations",
    "description": "Practice the quadratic formula on real problems.",
    "type": "ai-tutor",
    "quizCount": 0,
    "chapterSequence": 2
  }'
FieldTypeRequiredDescription
titlestringYesLesson title (≤ 255 chars)
typestringYesLesson type (ai-tutor, coding-lesson, coding-test, chat-ai, exam, flashcard, markdown)
descriptionstringNoLesson description (≤ 2000 chars)
quizCountnumberNoNumber of quizzes to auto-generate (0–20)
chapterSequencenumberNoChapter sequence to add the lesson to. Defaults to the last chapter.

Returns the created lesson as PlatformLessonPublicDto (id, sequence, title, type, chapterTitle, description, lectureContent, codeContent, quizzes, lessonSlug, chapterSlug).

Update Course

curl -X PATCH https://api.tutorflow.io/v1/platform/courses/edit/{editToken} \
  -H "Content-Type: application/json" \
  -d '{ "title": "New Title", "description": "Updated overview." }'
FieldTypeRequiredDescription
titlestringNoUpdated course title
descriptionstringNoUpdated course description

Returns { "success": true }.

Update Lesson

curl -X PATCH https://api.tutorflow.io/v1/platform/courses/edit/{editToken}/lessons/3 \
  -H "Content-Type: application/json" \
  -d '{ "lecture": "<p>Updated HTML</p>", "title": "Loops, Revisited" }'
FieldTypeRequiredDescription
lecturestringNoUpdated lecture HTML content
titlestringNoUpdated lesson title
descriptionstringNoUpdated lesson description
lessonSlugstringNoUpdated lesson slug

Returns { "success": true }.

Infer Lesson Type

Given a lesson title (and optional context), the AI returns the best lesson type to use. Useful when an editor wants to insert a new lesson without picking a type manually.

curl -X POST https://api.tutorflow.io/v1/platform/courses/edit/{editToken}/infer-type \
  -H "Content-Type: application/json" \
  -d '{
    "lessonTitle": "Practice: Factoring Polynomials",
    "lessonDescription": "Hands-on practice problems for factoring.",
    "courseTitle": "Intermediate Algebra",
    "courseDescription": "Algebra fundamentals for high school students.",
    "existingLessons": [
      { "title": "Welcome to Algebra", "type": "ai-tutor" },
      { "title": "Variables and Expressions", "type": "ai-tutor" }
    ]
  }'
FieldTypeRequiredDescription
lessonTitlestringYesTitle of the lesson being inferred
lessonDescriptionstringNoOptional description for additional context
courseTitlestringNoCourse title for context
courseDescriptionstringNoCourse description for context
existingLessonsarrayNoOther lessons in the course as { title, type } items

Response:

{ "type": "exam" }

Async Mode

Set mode: "async" to queue course generation as a background job. The response returns immediately with status: "PENDING" and a pollAfterMs value. Poll GET /v1/platform/courses/:id until isTerminal is true.

Idempotency

Pass an idempotencyKey in the request body or Idempotency-Key header to prevent duplicate course generation. Reusing the same key returns the original response with idempotentReplay: true.