Get Course Structure
Learn how to retrieve course structure, sections, lessons, and completion criteria using the Thought Industries REST API.
Overview
The Course Structure endpoints allow you to retrieve the complete hierarchical structure of a course, including:
- Course ID, title, and status
- Sections (with ID, title, releaseAt)
- Lessons within each section (with ID, title, accessLevel)
- Topics within each lesson (with ID, title, type)
- Completion criteria
Authentication
All requests require Bearer token authentication:
-H "Authorization: Bearer ${API_TOKEN}"
-H "Content-Type: application/json"
Get Complete Course Structure
Retrieve the full hierarchical course structure in a single request.
Endpoint
GET ${BASE_URL}/v2/courses/{courseId}/structure
Request Example
curl -X GET "${BASE_URL}/v2/courses/c76d5b5d-b7b1-4258-a116-07d9228884ca/structure" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json"
Response Example
{
"id": "c76d5b5d-b7b1-4258-a116-07d9228884ca",
"title": "Multi SCORM page course",
"status": "draft",
"sections": [
{
"id": "61ee198a-ccd8-4046-9fca-5717d88f2e93",
"title": "Section 1",
"releaseAt": null,
"lessons": [
{
"id": "93e6076b-ba84-4012-84ff-73c0367006e0",
"title": "To Begin",
"accessLevel": null,
"topics": [
{
"id": "1366501c-3740-4a30-9464-1a2f111499ee",
"title": "Getting Started",
"type": "text",
"editableByChildren": false
}
]
},
{
"id": "619004f9-213a-45e0-843d-c4c93db941de",
"title": "Lesson 1.2",
"accessLevel": null,
"topics": [
{
"id": "fdbec9af-e134-4c42-81c4-05a056dd40ca",
"title": "SCORM 1.2",
"type": "shareableContentObject",
"editableByChildren": false
},
{
"id": "ef8967dc-dace-4215-baf0-0258fcd2fff5",
"title": "Quiz 1.2",
"type": "quiz",
"editableByChildren": false
}
]
}
]
},
{
"id": "5c7a5ae8-afeb-4ddd-acf9-8aebd6328048",
"title": "Section 2",
"releaseAt": null,
"lessons": [
{
"id": "7d1a7a0f-574e-447b-9755-476ff007c880",
"title": "Exam and Conclusion",
"accessLevel": null,
"topics": [
{
"id": "fc36dc1d-d683-4760-ae8d-97809d3c30a8",
"title": "Final Exam",
"type": "test",
"editableByChildren": false
},
{
"id": "61237fd7-89d2-4bc3-9431-374dc5263edb",
"title": "Last page",
"type": "text",
"editableByChildren": false
}
]
}
]
}
],
"completionCriteria": [
{
"id": "5c13255a-e1ee-42ef-a79d-d4a7d839e578",
"type": "coursePercentViewed",
"coursePercentViewed": 90,
"articlePercentViewed": null,
"articleTimeViewedInSeconds": null,
"videoPercentViewed": null,
"courseAssignmentComplete": null,
"courseAssessmentPassed": null,
"courseTopicViewed": null,
"courseMeetingAttended": null,
"scormComplete": null,
"surveyGizmoComplete": null,
"xApiComplete": null,
"bongoAssignmentCompleted": null
},
{
"id": "4a33f62e-323f-4f9b-a502-40aadf39ef87",
"type": "courseAssessmentPassed",
"coursePercentViewed": null,
"articlePercentViewed": null,
"articleTimeViewedInSeconds": null,
"videoPercentViewed": null,
"courseAssignmentComplete": null,
"courseAssessmentPassed": "fc36dc1d-d683-4760-ae8d-97809d3c30a8",
"courseTopicViewed": null,
"courseMeetingAttended": null,
"scormComplete": null,
"surveyGizmoComplete": null,
"xApiComplete": null,
"bongoAssignmentCompleted": null
}
]
}
Get Course Sections
Retrieve only the sections of a course without nested lessons.
Endpoint
GET ${BASE_URL}/v2/courses/{courseId}/sections
Request Example
curl -X GET "${BASE_URL}/v2/courses/c76d5b5d-b7b1-4258-a116-07d9228884ca/sections" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json"
Response Example
{
"sections": [
{
"id": "61ee198a-ccd8-4046-9fca-5717d88f2e93",
"title": "Section 1",
"slug": "section-1",
"status": "published",
"releaseAt": null,
"parentSectionId": null,
"lessonCount": 3
},
{
"id": "5c7a5ae8-afeb-4ddd-acf9-8aebd6328048",
"title": "Section 2",
"slug": "section-2",
"status": "published",
"releaseAt": null,
"parentSectionId": null,
"lessonCount": 1
}
],
"pageInfo": {
"total": 2,
"currentPage": 1,
"perPage": 50,
"hasMore": false
}
}
Get Course Lessons
Retrieve all lessons within a course.
Endpoint
GET ${BASE_URL}/v2/courses/{courseId}/lessons
Request Example
curl -X GET "${BASE_URL}/v2/courses/c76d5b5d-b7b1-4258-a116-07d9228884ca/lessons" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json"
Response Example
{
"lessons": [
{
"id": "93e6076b-ba84-4012-84ff-73c0367006e0",
"title": "To Begin",
"slug": "to-begin",
"accessLevel": null,
"sectionId": "61ee198a-ccd8-4046-9fca-5717d88f2e93",
"sectionTitle": "Section 1",
"topicCount": 1
},
{
"id": "619004f9-213a-45e0-843d-c4c93db941de",
"title": "Lesson 1.2",
"slug": "lesson-12",
"accessLevel": null,
"sectionId": "61ee198a-ccd8-4046-9fca-5717d88f2e93",
"sectionTitle": "Section 1",
"topicCount": 2
},
{
"id": "cb52cdaf-19b2-4bb5-9f17-865de65474ee",
"title": "Lesson 1.3",
"slug": "lesson-13",
"accessLevel": null,
"sectionId": "61ee198a-ccd8-4046-9fca-5717d88f2e93",
"sectionTitle": "Section 1",
"topicCount": 2
},
{
"id": "7d1a7a0f-574e-447b-9755-476ff007c880",
"title": "Exam and Conclusion",
"slug": "exam-and-conclusion",
"accessLevel": null,
"sectionId": "5c7a5ae8-afeb-4ddd-acf9-8aebd6328048",
"sectionTitle": "Section 2",
"topicCount": 2
}
],
"pageInfo": {
"total": 4,
"currentPage": 1,
"perPage": 50,
"hasMore": false
}
}
Get Course Completion Criteria
Retrieve the completion criteria for a course.
Endpoint
GET ${BASE_URL}/v2/courses/{courseId}/completionCriteria
Request Example
curl -X GET "${BASE_URL}/v2/courses/c76d5b5d-b7b1-4258-a116-07d9228884ca/completionCriteria" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json"
Response Example
[
{
"id": "5c13255a-e1ee-42ef-a79d-d4a7d839e578",
"type": "coursePercentViewed",
"coursePercentViewed": 90,
"articlePercentViewed": null,
"articleTimeViewedInSeconds": null,
"videoPercentViewed": null,
"courseAssignmentComplete": null,
"courseAssessmentPassed": null,
"courseTopicViewed": null,
"courseMeetingAttended": null,
"scormComplete": null,
"surveyGizmoComplete": null,
"xApiComplete": null,
"bongoAssignmentCompleted": null
},
{
"id": "4a33f62e-323f-4f9b-a502-40aadf39ef87",
"type": "courseAssessmentPassed",
"coursePercentViewed": null,
"articlePercentViewed": null,
"articleTimeViewedInSeconds": null,
"videoPercentViewed": null,
"courseAssignmentComplete": null,
"courseAssessmentPassed": "fc36dc1d-d683-4760-ae8d-97809d3c30a8",
"courseTopicViewed": null,
"courseMeetingAttended": null,
"scormComplete": null,
"surveyGizmoComplete": null,
"xApiComplete": null,
"bongoAssignmentCompleted": null
}
]
Complete Endpoint Reference
Course Groups
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/courseGroups | List all course groups |
| GET | /v2/courseGroups/:id | Get specific course group by ID |
| GET | /v2/courseGroups/slug/:slug | Get course group by slug |
| GET | /v2/courseGroups/:id/courses | List courses in a course group |
| GET | /v2/courseGroups/:id/displayCourse | Get display course for group |
Courses
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/courses/:courseId/structure | Get complete course structure |
| GET | /v2/courses/:courseId/sections | Get course sections |
| GET | /v2/courses/:courseId/lessons | Get course lessons |
| GET | /v2/courses/:courseId/completionCriteria | Get completion criteria |
Sections
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/sections/:id | Get specific section |
| GET | /v2/sections/:sectionId/lessons | Get lessons in a section |
Lessons
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/lessons/:id | Get specific lesson |
Topics
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/topics/:id | Get specific topic |
| GET | /v2/topics/course/:courseId | Get all topics in a course |
| GET | /v2/topics/lesson/:lessonId | Get all topics in a lesson |
Content (Generic)
| Method | Endpoint | Description |
|---|---|---|
| GET | /v2/content | List all content |
| GET | /v2/content/:type/:id | Get specific content by type and ID |
| GET | /v2/fullContent/:type/:id | Get full content details |
Topic Types Reference
Topics can have various types:
text- Text contentvideo- Video contentquiz- Quiz/assessmenttest- Test/examshareableContentObject- SCORM contentassignment- Assignmentmeeting- Live meeting/webinarsurvey- SurveyxApi- xAPI/Tin Can content
Completion Criteria Types
Completion criteria can be based on:
coursePercentViewed- Percentage of course viewedarticlePercentViewed- Percentage of article viewedarticleTimeViewedInSeconds- Time spent viewing articlevideoPercentViewed- Percentage of video viewedcourseAssignmentComplete- Assignment completioncourseAssessmentPassed- Assessment passedcourseTopicViewed- Specific topic viewedcourseMeetingAttended- Meeting attendedscormComplete- SCORM completionsurveyGizmoComplete- Survey completionxApiComplete- xAPI completionbongoAssignmentCompleted- Bongo assignment completion
Use Cases
Displaying Course Outline
Use the structure endpoint to build a course outline for learners:
async function getCourseOutline(courseId) {
const response = await fetch(
`${BASE_URL}/v2/courses/${courseId}/structure`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
}
);
const structure = await response.json();
// Build navigation
const outline = structure.sections.map(section => ({
title: section.title,
lessons: section.lessons.map(lesson => ({
title: lesson.title,
topics: lesson.topics.map(topic => ({
title: topic.title,
type: topic.type
}))
}))
}));
return outline;
}
Checking Course Progress
Combine structure with completion criteria to track progress:
async function checkCourseProgress(courseId, userId) {
// Get structure
const structure = await fetch(
`${BASE_URL}/v2/courses/${courseId}/structure`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
}
).then(r => r.json());
// Get completion criteria
const criteria = await fetch(
`${BASE_URL}/v2/courses/${courseId}/completionCriteria`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
}
).then(r => r.json());
// Calculate what's required for completion
const requirements = criteria.map(c => ({
type: c.type,
value: c[c.type]
}));
return {
structure,
requirements
};
}
Building Custom Navigation
Create a custom course navigation from sections and lessons:
async function buildCourseNavigation(courseId) {
const response = await fetch(
`${BASE_URL}/v2/courses/${courseId}/lessons`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
}
);
const { lessons } = await response.json();
// Group by section
const navigation = lessons.reduce((acc, lesson) => {
const section = lesson.sectionTitle;
if (!acc[section]) {
acc[section] = [];
}
acc[section].push({
id: lesson.id,
title: lesson.title,
slug: lesson.slug,
topicCount: lesson.topicCount
});
return acc;
}, {});
return navigation;
}
Pagination
Endpoints that return lists support pagination:
Query Parameters
page- Page number (default: 1)perPage- Items per page (default: 50, max: 100)
Example
curl -X GET "${BASE_URL}/v2/courses/${courseId}/lessons?page=2&perPage=25" \
-H "Authorization: Bearer ${API_TOKEN}" \
-H "Content-Type: application/json"
Response Structure
{
"lessons": [...],
"pageInfo": {
"total": 100,
"currentPage": 2,
"perPage": 25,
"hasMore": true
}
}
Error Handling
Common Errors
404 Not Found
{
"error": "NotFound",
"message": "Course not found",
"courseId": "invalid-id"
}
401 Unauthorized
{
"error": "Unauthorized",
"message": "Invalid or missing API token"
}
403 Forbidden
{
"error": "Forbidden",
"message": "Insufficient permissions to access this course"
}
Best Practices
1. Use Structure Endpoint for Complete Data
When you need full course hierarchy, use /structure:
- ✅ Single API call
- ✅ Complete nested data
- ✅ Better performance
2. Use Specific Endpoints for Partial Data
When you only need sections or lessons:
- ✅ Smaller response payload
- ✅ Faster response time
- ✅ Better for pagination
3. Cache Structure Data
Course structure changes infrequently:
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function getCachedStructure(courseId) {
const cached = cache.get(courseId);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const data = await fetchCourseStructure(courseId);
cache.set(courseId, {
data,
timestamp: Date.now()
});
return data;
}
4. Handle Pagination Properly
For courses with many lessons:
async function getAllLessons(courseId) {
let page = 1;
let hasMore = true;
const allLessons = [];
while (hasMore) {
const response = await fetch(
`${BASE_URL}/v2/courses/${courseId}/lessons?page=${page}&perPage=50`,
{
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
}
);
const { lessons, pageInfo } = await response.json();
allLessons.push(...lessons);
hasMore = pageInfo.hasMore;
page++;
}
return allLessons;
}
Next Steps
- Learn about Creating Courses
- Explore Course Examples
- Review Field Reference