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:
| Tier | Price |
|---|---|
basic | $0.10 |
standard | $0.25 |
advanced | $0.50 |
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:
| Type | Description | Best for |
|---|---|---|
coding-lesson | Hands-on coding tutorial with IDE | Programming topics |
coding-test | Coding exercise/challenge | Programming practice |
chat-ai | AI tutor conversation | Soft skills, exploration |
flashcard | Review/vocabulary cards | Language learning, key concepts |
exam | Quiz/assessment | End-of-chapter review |
markdown | Text-only reading | Course overview, reference material |
For programming courses, at least 70% of lessons use coding-lesson or coding-test.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | Prompt describing the course to generate |
title | string | No | Override AI-generated title |
description | string | No | Override AI-generated description |
language | string | No | Course language (default: en) |
level | string | No | beginner, intermediate, or advanced |
subject | string | No | Subject area |
lessonCount | number | No | Target number of lessons for AI to generate |
classroomId | string | No | Classroom ID to create the course in. Uses the default classroom if omitted |
tier | string | No | basic, standard, or advanced. Defaults to standard |
idempotencyKey | string | No | Prevents duplicate processing. Can also be sent via Idempotency-Key HTTP header |
mode | string | No | sync (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
| Field | Type | Description |
|---|---|---|
id | string | Platform course request ID |
status | string | PENDING, PROCESSING, COMPLETED, or FAILED |
courseId | string | Actual course ID in TutorFlow (once created) |
title | string | Course title |
description | string | Course description |
level | string | Difficulty level |
slug | string | URL-friendly course slug |
tier | string | Pricing tier used |
priceSnapshot | object | Pricing details captured at request time |
chapters | array | Chapter summaries with title, sequence, slug, and lesson count |
lessons | array | Lesson summaries with title, type, sequence, chapter, slugs, and lessonUrl |
editUrl | string | Token-based edit URL (valid for 1 hour, no login required) |
previewUrl | string | Public preview URL (no login required, no expiry) |
isTerminal | boolean | Whether the request has reached a final state |
pollAfterMs | number | Recommended polling interval for async requests |
idempotencyKey | string | Echoed idempotency key |
idempotentReplay | boolean | true if this response reused an existing request |
createdAt | string | ISO 8601 timestamp |
completedAt | string | ISO 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.",
"level": "beginner",
"slug": "python-quick-start-2e5ad6",
"tier": "standard",
"editUrl": "https://tutorflow.io/en/platform/courses/edit/51d9b322e680...",
"previewUrl": "https://tutorflow.io/en/platform/courses/b018172542f9...",
"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": "Understanding Variables", "type": "coding-lesson", "sequence": 1, "chapterTitle": "Introduction to Variables", "lessonSlug": "understanding-variables-29ae64", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/1" },
{ "title": "Variable Practice", "type": "coding-test", "sequence": 2, "chapterTitle": "Introduction to Variables", "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", "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", "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", "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", "lessonSlug": "function-exercises-0a1b2c", "lessonUrl": "https://tutorflow.io/en/platform/courses/b018.../lessons/6" }
],
"isTerminal": true,
"createdAt": "2026-03-24T10:32:15.108Z",
"completedAt": "2026-03-24T10:32:37.671Z"
}Edit URL vs Preview URL
| URL | Purpose | Auth | Expiry |
|---|---|---|---|
editUrl | Full course editor with lesson content, coding IDE, and curriculum settings | Token-based, no login | 1 hour |
previewUrl | Read-only course viewer for learners | Public, no login | None |
The editUrl is a token-based link valid for 1 hour. Anyone with the link can edit the course
(lesson content, title, description, curriculum structure) without logging in. When the token
expires, generate a new one via POST /v1/platform/courses/:id/edit-token.
The previewUrl is permanent and safe to share publicly with learners. Each lesson in the
response also includes a lessonUrl that links directly to that lesson in the preview.
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...",
"editUrl": "https://tutorflow.io/en/platform/courses/edit/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):
| Method | Path | Description |
|---|---|---|
GET | /v1/platform/courses/edit/:editToken | Get course summary |
GET | /v1/platform/courses/edit/:editToken/full | Get full course with all lesson content |
GET | /v1/platform/courses/edit/:editToken/lessons/:sequence | Get single lesson |
PATCH | /v1/platform/courses/edit/:editToken | Update course title/description |
PATCH | /v1/platform/courses/edit/:editToken/lessons/:sequence | Update lesson content, title, slug, or description |
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.