Playground ↗ Postman ↗ Dashboard ↗
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

HeaderRequiredNotes
X-API-KeyyesYour test or production key
X-External-User-Idyes (or X-User-Id)Identifies the learner
Content-Typeyesmultipart/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_urls JSON, too many files, or invalid organization.
  • 429 — Tenant or user rate limit. Backoff per Retry-After.