POST /v2/courses/generate-from-files
Generate a course from files, YouTube, and web URLs
Creates a course from any combination of uploaded files, YouTube video URLs, and web pages — in a single request. Nuton ingests each source, indexes the content, and assembles a coherent course on top of it.
Unlike POST /v2/courses/generate, this endpoint uses multipart/form-data, not JSON.
Request
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | yes | Your test or production key |
X-External-User-Id | yes (or X-User-Id) | Identifies the learner |
Content-Type | yes | multipart/form-data; boundary=… |
Form fields
files file[] Up to 10 files. Supported: PDF, DOCX, PPTX/PPT, TXT, MD, PNG, JPG, WEBP. Max 50MB each. |
youtube_urls string JSON-encoded array of YouTube video URLs, e.g. ["https://youtu.be/abc123"]. |
web_urls string JSON-encoded array of web page URLs. Nuton fetches and extracts the readable content. |
topic string Optional learner-facing topic that frames the course. Falls back to the dominant theme of the sources. |
organization enum default auto One of auto, thematic_bridge, sequential_sections, separate_courses. Controls how multi-source content is stitched together. |
num_chapters integer default 4 Number of chapters to generate (1–20). |
search_enabled boolean default true Augments chapters with web search when the model supports it. |
learning_goal enum Optional. One of exams, career, curiosity, supplement. |
Query parameters
mode enum default async async returns a job ID; sync blocks until done; stream emits SSE. |
Example
curl -X POST "https://api.nuton.app/v2/courses/generate-from-files?mode=async" \
-H "X-API-Key: $NUTON_KEY" \
-H "X-External-User-Id: alice@example.com" \
-F "files=@chapter1.pdf" \
-F "files=@chapter2.pdf" \
-F "youtube_urls=[\"https://youtu.be/kwSVtQ7dziU\"]" \
-F "web_urls=[\"https://en.wikipedia.org/wiki/Photosynthesis\"]" \
-F "topic=Photosynthesis fundamentals" \
-F "num_chapters=5"
Returns
Same response shape as POST /v2/courses/generate. In async mode you get a job_id; in sync mode you get the full course; in stream mode you get a sequence of SSE events.
File ingestion can take 30–60s for large PDFs. Prefer ?mode=async for anything over a single short doc — poll GET /v2/courses/{course_id}/progress or wait for a course.completed webhook.
Errors
- 413 — Total upload exceeds the 500MB combined limit.
- 415 — Unsupported file format.
- 422 — Malformed
youtube_urls/web_urlsJSON, too many files, or invalidorganization. - 429 — Tenant or user rate limit. Backoff per
Retry-After.