Export Lesson
Export a published lesson version as a self-contained ZIP file containing all lesson content, media assets, and widget bundles.
EdTech Plan Required
Lesson export is available on EdTech plans only. Organizations on a Solo plan will receive a 403 Forbidden response with the code FEATURE_NOT_AVAILABLE. Contact your organization admin to upgrade if you need export access.
Endpoint
GET /api/lessons/{lessonId}/versions/{versionId}/export-zipAuthentication
This endpoint requires authentication using a Bearer token. See Authentication for complete details on API token format, usage, and error handling.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
lessonId | string (UUID) | Yes | The unique identifier of the lesson |
versionId | string (UUID) | Yes | The unique identifier of the published version |
Response
Success Response (200 OK)
Returns a ZIP file as a binary download.
Response Headers:
| Header | Value |
|---|---|
Content-Type | application/zip |
Content-Disposition | attachment; filename="lesson-slug-v1.zip" |
Content-Length | Size of the ZIP file in bytes |
ZIP File Structure
The exported ZIP contains the following structure:
lesson-slug-v1/
├── lesson.json # Lesson content with localized media references
├── manifest.json # Export metadata and file inventory
├── styles/
│ └── custom.css # Lesson custom CSS (if the lesson has any)
├── media/
│ ├── {uuid}.jpg # Media files (images, audio)
│ ├── {uuid}.png
│ └── ...
├── videos/
│ └── {uuid}/
│ ├── video.mp4 # Library videos (Video Player components)
│ └── thumbnail.jpg
└── widgets/
├── {widget-id}.js # Widget JavaScript bundles
├── {widget-id}.css # Widget CSS files (if available)
└── ...lesson.json
Contains the full lesson content structure. All media references are rewritten from media:{uuid} format to local paths (./media/{uuid}.{ext}).
manifest.json
Contains export metadata and file inventory:
{
"lessonId": "550e8400-e29b-41d4-a716-446655440000",
"title": "Introduction to Biology",
"versionNumber": 1,
"versionId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"publishedAt": "2025-01-15T10:30:00Z",
"exportedAt": "2025-01-20T14:45:00Z",
"formatVersion": "1.0.0",
"files": {
"lesson": "./lesson.json",
"media": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"localPath": "./media/a1b2c3d4-e5f6-7890-abcd-ef1234567890.jpg",
"mimeType": "image/jpeg"
}
],
"widgets": [
{
"widgetType": "multiple-choice",
"localPath": "./widgets/widget-123.js",
"cssLocalPath": "./widgets/widget-123.css"
}
]
},
"fonts": {
"display": {
"family": "Lobster",
"category": "display",
"variants": ["400"],
"fontFamily": "\"Lobster\", system-ui, sans-serif"
},
"body": null,
"googleFontsUrl": "https://fonts.googleapis.com/css2?family=Lobster&display=swap"
},
"failedMedia": [],
"failedWidgets": [],
"attributions": [
{
"mediaId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"text": "Photo by John Doe",
"url": "https://unsplash.com/photos/abc123",
"portfolioUrl": "https://unsplash.com/@johndoe"
}
]
}Error Responses
400 Bad Request
The path parameters are invalid.
{
"error": "Bad Request",
"message": "Invalid lesson ID",
"code": "BAD_REQUEST",
"timestamp": "2025-01-20T14:45:00.000Z"
}401 Unauthorized
Authentication failed. See Authentication Errors for detailed information.
{
"error": "Authentication Error",
"message": "User authentication is required",
"code": "UNAUTHORIZED",
"timestamp": "2025-01-20T14:45:00.000Z"
}403 Forbidden
The organization’s plan does not include lesson export. This applies to Solo plan organizations.
{
"error": "Forbidden",
"message": "Lesson export is not available on your current plan. Upgrade to an EdTech plan to export lessons.",
"code": "FEATURE_NOT_AVAILABLE",
"timestamp": "2025-01-20T14:45:00.000Z"
}404 Not Found
The specified lesson or version does not exist, or is not accessible by the authenticated user.
{
"error": "Not Found",
"message": "Published version not found",
"code": "NOT_FOUND",
"timestamp": "2025-01-20T14:45:00.000Z"
}422 Unprocessable Entity
The published version content is invalid or empty.
{
"error": "Invalid Content",
"message": "Published version content is invalid or empty",
"code": "INVALID_CONTENT",
"timestamp": "2025-01-20T14:45:00.000Z"
}500 Internal Server Error
An unexpected error occurred during export.
{
"error": "Internal Server Error",
"message": "An unexpected error occurred while generating export ZIP",
"code": "INTERNAL_ERROR",
"timestamp": "2025-01-20T14:45:00.000Z"
}Example Requests
Download Lesson Export
curl -X GET 'https://app.teacharium.io/api/lessons/550e8400-e29b-41d4-a716-446655440000/versions/6ba7b810-9dad-11d1-80b4-00c04fd430c8/export-zip' \
-H 'Authorization: Bearer tapub_xxxxx.tasec_xxxxx' \
-o lesson-export.zipUsing wget
wget --header='Authorization: Bearer tapub_xxxxx.tasec_xxxxx' \
'https://app.teacharium.io/api/lessons/550e8400-e29b-41d4-a716-446655440000/versions/6ba7b810-9dad-11d1-80b4-00c04fd430c8/export-zip' \
-O lesson-export.zipRelated Endpoints
Export Manifest
If you need to download assets individually or implement custom export logic, you can use the manifest endpoint:
GET /api/lessons/{lessonId}/versions/{versionId}/export-manifestThis returns a JSON manifest with signed URLs for all assets (valid for 4 hours), allowing you to download files individually.
Export SCORM Package
To deliver a lesson through an LMS (Moodle, Canvas, Cornerstone, SCORM Cloud and others), export it as a SCORM package instead:
GET /api/lessons/{lessonId}/versions/{versionId}/export-scorm?version=1.2| Query Parameter | Values | Default | Description |
|---|---|---|---|
version | 1.2 or 2004 | 1.2 | SCORM version of the package. SCORM 2004 packages use the 4th Edition manifest schema. |
The response is a ZIP to upload to your LMS as-is. It contains everything in the lesson export above, at the root of the ZIP, plus:
| File | Purpose |
|---|---|
imsmanifest.xml | SCORM manifest with a single SCO that launches index.html |
index.html, runtime/ | A self-contained lesson player |
react-shim.js, react-dom-shim.js | Let the widget bundles share the player’s React |
scorm.json | The SCORM version the package was exported for |
The player reports to the LMS:
- Status:
incompletewhen the learner starts, thencompletedat the end. If the lesson is scored and the LMS sets a passing score (cmi.student_data.mastery_scorein SCORM 1.2,cmi.scaled_passing_scorein SCORM 2004), the result ispassedorfailedinstead. - Score: SCORM 1.2 gets a percentage (0–100). SCORM 2004 gets the raw score, its maximum and the scaled score (0–1).
- Resume: the learner’s progress is saved in
cmi.suspend_dataat every step, so they continue where they left off. SCORM 1.2 allows only 4,096 characters, so long lessons are compressed and, if still too long, only the current step and variables are kept. - Review: relaunching a finished attempt opens it in review mode when the LMS keeps its data.
- Session time and exit when the learner leaves.
Fonts are loaded from Google Fonts, as in the lesson export, so learners need internet access for custom lesson fonts.
Notes
- Only published lesson versions can be exported
- The ZIP file includes all media assets and widget bundles required to play the lesson offline
- Media references in
lesson.jsonare automatically rewritten to use local paths - External media (e.g., from Unsplash) is downloaded and included in the ZIP
- Attribution information for external media is preserved in
manifest.json - Font files are not included. If the lesson uses custom fonts,
manifest.jsonhas afontsentry (omitted otherwise) with the font families and a ready-made Google Fonts URL; your page must load them. See Lesson Fonts - Large exports may take several seconds to generate on the server
- The
failedMediaandfailedWidgetsarrays in the manifest indicate any assets that could not be downloaded - This endpoint is only available to organizations on an EdTech plan. Solo plan organizations should use hosted embedding or LTI integration instead