Skip to main content
https://.thoughtindustries.com

Create Courses

Creates one or more courses (up to 100 courses per request, with a maximum of 25 children per course). Children include sections, lessons, and topics. The endpoint automatically creates the full course hierarchy including the course group, course (session), sections, lessons, and topics based on the `kind` specified.

Creates one or more courses (up to 100 courses per request, with a maximum of 25 children per course). Children include sections, lessons, and topics. The endpoint automatically creates the full course hierarchy including the course group, course (session), sections, lessons, and topics based on the kind specified.

Authentication & Permissions

Authenticate with Authorization: Bearer YOUR_API_KEY. This endpoint requires the courses.new permission. This route is not rate limited.

Course Attributes

PropertyTypeRequired?Description
titlestringyesTitle of the course
kindstringyesCourse type: courseGroup, microCourse, article, video, shareableContentObject (5 kinds). xApiObject is not a valid course kind — it is only a topic type
skustringnoUnique SKU identifier
isbnstringnoISBN number
discussionsEnabledbooleannoEnable course discussions
availableToPublicbooleannoMake course available without login
enrollmentLimitintegernoMaximum number of enrollments (enables seat limits)
enrollmentStartDatedatenoWhen enrollment opens (ISO 8601)
enrollmentEndDatedatenoWhen enrollment closes (ISO 8601)
courseStartDatedatenoWhen the course starts (ISO 8601)
courseEndDatedatenoWhen the course ends (ISO 8601)
gracePeriodEndDatedatenoGrace period end date (ISO 8601)
sectionsarraynoArray of section objects (for courseGroup kind)
topicsarraynoArray of topic objects (for microCourse kind)
articleVariantobjectnoArticle content (for article kind)
widthintegernoDisplay width for SCORM/xAPI (pixels)
heightintegernoDisplay height for SCORM/xAPI (pixels)
embeddedEnabledbooleannoEnable embedded display for SCORM/xAPI
resetSessionAfterCompletebooleannoReset SCORM session after completion
scormUrlURLnoURL to SCORM/xAPI package (for standalone SCORM courses)
videoUrlURLnoExternal video URL for video kind — downloaded and uploaded to Wistia by a background job. Set at the course (top) level, not in topics
videoAssetIDnoExisting Wistia media ID or Synthesia UUID for video kind. Mutually exclusive with videoUrl. Course-level
assetTypestringnoVideo provider for video kind: wistia (default) or synthesia. Required for Synthesia. Course-level
preAssetIDnoWistia media ID for pre-roll video (video kind). Course-level
postAssetIDnoWistia media ID for post-roll video (video kind). Course-level
posterImageAssetURLnoPoster image URL shown before the video plays (video kind). Course-level

Catalog & Session Attributes (live in production):

CourseGroup-Level (Catalog) Attributes:

PropertyTypeDescription
descriptionstringCourse description for catalog and detail pages (max 5,000 characters)
tagIdsarrayArray of tag UUIDs for categorization (max 10). Tags must already exist on the company. Use GET /tags to list available IDs
customFieldsJSONCustom field values as {"slug": "value" or ["v1", "v2"]}. Replaces the entire object on update
assetURLCatalog thumbnail image URL (recommended: 800x385px, PNG/JPEG/GIF). Downloaded and uploaded to S3
assetAltTextstringAlt text for catalog image. Defaults to empty string when asset is provided
detailAssetURLDetail page image URL (recommended: 800x450px, PNG/JPEG/GIF). Downloaded and uploaded to S3
detailAssetAltTextstringAlt text for detail image. Defaults to empty string when detailAsset is provided
ribbonstringRibbon badge slug (e.g., new, popular). Must exist in the company's ribbon configuration
metaTitlestringSEO meta title (max 200 characters, HTML stripped)
metaDescriptionstringSEO meta description (max 500 characters, HTML stripped)
contentTypestringContent type label (e.g., "Training Module"). Auto-derived from kind if omitted; must exist in the company's configuration
relatedCourseGroupIdsarrayRelated catalog course group UUIDs. Must exist on the company

Course-Level (Session) Attributes:

PropertyTypeDescription
priceInCentsintegerPrice in cents (e.g., 9900 = $99.00). Max: 99,999,999. Cannot be negative
freeWithRegistrationbooleanFree access for all registered users (default: false)
purchasablebooleanEnable purchase functionality (default: false)
statusstringdraft or published; omit to default to draft. With futurePublishDate, status becomes pending for scheduled release
futurePublishDatedateAuto-publish the session to the catalog at this date. Implies pending unless status is published
publishDatedateCourse group catalog date used for search/display ordering
sessionCustomFieldsJSONSession-level custom field values. Replaces the entire object on update
forceLinearProgressbooleanForce learners to complete pages in order (default: false)
showProgressbooleanShow progress indicator to learners (default: true)
prerequisiteCourseIdsarrayPrerequisite course UUIDs. Must exist on the company
prerequisiteLearningPathIdsarrayPrerequisite learning path UUIDs. Must exist on the company

Section Object

PropertyTypeRequired?Description
titlestringyesSection title
releaseDatedatenoWhen section is released
lessonsarrayyesArray of lesson objects

Lesson Object

PropertyTypeRequired?Description
titlestringyesLesson title
openTypestringyesAccess level: studentsOnly, open, emailCaptureOpen
topicsarrayyesArray of topic objects

Topic Object

PropertyTypeRequired?Description
titlestringyesTopic title
typestringyesTopic type (see Supported Topic Types below)
bodystringnoHTML content (for text/article topics)
languagesarraynoMulti-language content variants
preTextBlockstringnoText displayed before topic content
postTextBlockstringnoText displayed after topic content
widthintegernoDisplay width (pixels)
heightintegernoDisplay height (pixels)
embeddedEnabledbooleannoEnable embedded display
fullscreenEmbedbooleannoEnable fullscreen embed
preventProgressionbooleannoPrevent learner from advancing until complete
resetSessionAfterCompletebooleannoReset session after completion (SCORM)
captionstringnoCaption text
searchDisabledbooleannoExclude from search
printDisabledbooleannoDisable printing
fileDownloadDisabledbooleannoDisable file download
scormUrlURLnoURL to SCORM/xAPI package (for shareableContentObject/xApiObject)
scoTitlestringnoSCORM title
objectTypestringnoSCORM standard type
courseCompletionCriteriaobjectnoCompletion criteria for the topic
pdfUrlURLnoURL to PDF file (for pdfViewer type)
videoUrlURLnoExternal URL to a video file (for video type) — uploaded to Wistia by a background job
videoAssetIDnoExisting Wistia media ID or Synthesia UUID (for video type). Mutually exclusive with videoUrl
assetTypestringnoVideo provider: wistia (default) or synthesia. Required when videoAsset is a Synthesia ID
preAssetIDnoWistia media ID for pre-roll video
postAssetIDnoWistia media ID for post-roll video
posterImageAssetURLnoPoster image URL displayed before the video plays
audioUrlURLnoComing soon - URL to audio file (for audio type)

Supported Topic Types

Fully Supported (content can be created via API):

TypeDescription
textRich text content (use body field)
articleArticle page (use body or languages field)
videoVideo page (use videoUrl to upload, or videoAsset to reference existing)
shareableContentObjectSCORM content (use scormUrl field)
xApiObjectxAPI content (use scormUrl field)
pdfViewerPDF document (use pdfUrl field)
embedEmbedded content (use body with iframe)
discussionBoardDiscussion forum

Shell Only (creates placeholder, content must be added via UI):

TypeDescription
quizQuiz - questions must be added via UI
testAssessment - questions must be added via UI
surveySurvey - questions must be added via UI
assignmentAssignment - configuration required via UI
audioAudio page - coming soon via API
imageImage gallery - configuration via UI
slideshowSlideshow - configuration via UI
presentationPresentation - configuration via UI
meetingInfoMeeting information - linked to calendar event
POST https://example.thoughtindustries.com/incoming/v2/content/course/create

Example request - Standard Course

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Introduction to Marketing",
      "kind": "courseGroup",
      "sku": "MKT-101",
      "discussionsEnabled": true,
      "sections": [
        {
          "title": "Getting Started",
          "lessons": [
            {
              "title": "Welcome",
              "openType": "studentsOnly",
              "topics": [
                {
                  "title": "Course Overview",
                  "type": "text",
                  "body": "<p>Welcome to the course!</p>"
                },
                {
                  "title": "Embedded Media",
                  "type": "embed",
                  "body": "<iframe src=\"https://player.vimeo.com/video/123456\" width=\"640\" height=\"360\"></iframe>"
                }
              ]
            }
          ]
        },
        {
          "title": "Core Concepts",
          "lessons": [
            {
              "title": "Marketing Fundamentals",
              "openType": "studentsOnly",
              "topics": [
                {
                  "title": "The 4 Ps of Marketing",
                  "type": "article",
                  "body": "<h2>Product, Price, Place, Promotion</h2><p>...</p>"
                },
                {
                  "title": "Knowledge Check",
                  "type": "quiz"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}'

Example response - Standard Course

The response is always an object containing the created course and course group IDs:

{
  "courseIds": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
  "courseGroupIds": ["b2c3d4e5-f6a7-8901-bcde-f23456789012"]
}

Example request - Micro Course

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Quick Tips: Email Etiquette",
      "kind": "microCourse",
      "topics": [
        {
          "title": "Subject Lines",
          "type": "text",
          "body": "<p>Keep subject lines clear and concise.</p>"
        },
        {
          "title": "Professional Tone",
          "type": "text",
          "body": "<p>Maintain a professional tone in all communications.</p>"
        },
        {
          "title": "Quiz",
          "type": "quiz"
        }
      ]
    }
  ]
}'

Example request - Standalone SCORM Course

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Compliance Training Module",
      "kind": "shareableContentObject",
      "sku": "COMP-2024",
      "width": 1024,
      "height": 768,
      "embeddedEnabled": true,
      "scormUrl": "https://example.com/scorm-packages/compliance-2024.zip"
    }
  ]
}'

Example response - SCORM Course with Background Job

When uploading SCORM content, the response includes background job information:

{
  "courseIds": ["b2c3d4e5-f6a7-8901-bcde-f23456789012"],
  "courseGroupIds": ["c3d4e5f6-a7b8-9012-cdef-345678901234"],
  "backgroundJob": {
    "id": "job-uuid-here",
    "type": "contentBulkUpload",
    "status": "queued",
    "contentUploads": [
      {
        "topicId": "topic-uuid-here",
        "courseId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
        "contentType": "scorm"
      }
    ]
  }
}

Example request - Article

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Best Practices for Remote Work",
      "kind": "article",
      "articleVariant": {
        "body": "<h1>Working from Home</h1><p>Here are the best practices...</p>"
      }
    }
  ]
}'

Example request - Standalone Video Course (upload from URL)

For kind: "video", the video fields (videoUrl, videoAsset, assetType, preAsset, postAsset, posterImageAsset) are set at the course (top) level — not inside a topics array. videoUrl and videoAsset are mutually exclusive, and assetType cannot be combined with videoUrl; violations return a 400 error. The platform downloads the file at videoUrl and uploads it to Wistia in a background job. Poll /v2/jobs/{id} to track the upload.

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Welcome Video",
      "kind": "video",
      "sku": "VID-001",
      "videoUrl": "https://example.com/videos/welcome.mp4",
      "posterImageAsset": "https://example.com/images/welcome-poster.jpg"
    }
  ]
}'

Example response - Video Course with Background Job

{
  "courseIds": ["c3d4e5f6-a7b8-9012-cdef-345678901234"],
  "courseGroupIds": ["d4e5f6a7-b8c9-0123-defa-456789012345"],
  "backgroundJob": {
    "id": "job-uuid-here",
    "type": "contentBulkUpload",
    "status": "queued",
    "contentUploads": [
      {
        "topicId": "topic-uuid-here",
        "courseId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
        "contentType": "video"
      }
    ]
  }
}

Example request - Standalone Video Course (existing Wistia media)

To reuse a video already uploaded to Wistia, pass videoAsset (the Wistia media ID) instead of videoUrl. No background job is queued.

curl -X "POST" "https://example.thoughtindustries.com/incoming/v2/content/course/create" \
     -H 'Authorization: Bearer YOUR_API_KEY' \
     -H 'Content-Type: application/json' \
     -d '{
  "courseAttributes": [
    {
      "title": "Product Demo",
      "kind": "video",
      "videoAsset": "abc123wistia",
      "preAsset": "intro456wistia",
      "postAsset": "outro789wistia"
    }
  ]
}'

Errors

Validation failures return HTTP 400 with an errors array. For a single course the array has one message; for multiple courses each message is prefixed with Course at index N:.

{
  "errors": [
    "Invalid course kinds: xApiObject. Supported kinds are: article, video, courseGroup, microCourse, shareableContentObject"
  ]
}